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
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
def runBeckGridlab(): try: os.remove('./beckDebuggery') except: pass os.mkdir('./beckDebuggery') rawOut = gridlabd.runInFilesystem(tree, attachments=myFeeder.get('attachments',{}), keepFiles=True, workDir='./beckDebuggery', glmName=None)
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
def runBeckGridlab(): try: os.remove('./beckDebuggery') except: pass os.mkdir('./beckDebuggery') rawOut = gridlabd.runInFilesystem(tree, attachments=myFeeder.get( 'attachments', {}), keepFiles=True, workDir='./beckDebuggery', glmName=None)
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
def convertTests(): ''' Test convert every windmil feeder we have (in uploads). Return number of exceptions we hit. ''' exceptionCount = 0 testFiles = [('OrvilleTreePond.std', 'OrvilleTreePond.seq')] # ,('OlinBarre.std','OlinBarre.seq'),('OlinBeckenham.std','OlinBeckenham.seq'), ('AutocliAlberich.std','AutocliAlberich.seq') for stdString, seqString in testFiles: try: # Convert the std+seq. with open(stdString, 'r') as stdFile, open(seqString, 'r') as seqFile: outGlm, x, y = milToGridlab.convert(stdFile.read(), seqFile.read()) with open(stdString.replace('.std', '.glm'), 'w') as outFile: outFile.write(feeder.sortedWrite(outGlm)) print 'WROTE GLM FOR', stdString try: # Draw the GLM. myGraph = feeder.treeToNxGraph(outGlm) feeder.latLonNxGraph(myGraph, neatoLayout=False) plt.savefig(stdString.replace('.std', '.png')) print 'DREW GLM OF', stdString except: exceptionCount += 1 print 'FAILED DRAWING', stdString try: # Run powerflow on the GLM. output = gridlabd.runInFilesystem(outGlm, keepFiles=False) with open(stdString.replace('.std', '.json'), 'w') as outFile: json.dump(output, outFile, indent=4) print 'RAN GRIDLAB ON', stdString except: exceptionCount += 1 print 'POWERFLOW FAILED', stdString except: print 'FAILED CONVERTING', stdString exceptionCount += 1 traceback.print_exc() print exceptionCount
def convertTests(): ''' Test convert every windmil feeder we have (in uploads). Return number of exceptions we hit. ''' exceptionCount = 0 testFiles = [('OrvilleTreePond.std','OrvilleTreePond.seq')] # ,('OlinBarre.std','OlinBarre.seq'),('OlinBeckenham.std','OlinBeckenham.seq'), ('AutocliAlberich.std','AutocliAlberich.seq') for stdString, seqString in testFiles: try: # Convert the std+seq. with open(stdString,'r') as stdFile, open(seqString,'r') as seqFile: outGlm,x,y = milToGridlab.convert(stdFile.read(),seqFile.read()) with open(stdString.replace('.std','.glm'),'w') as outFile: outFile.write(feeder.sortedWrite(outGlm)) print 'WROTE GLM FOR', stdString try: # Draw the GLM. myGraph = feeder.treeToNxGraph(outGlm) feeder.latLonNxGraph(myGraph, neatoLayout=False) plt.savefig(stdString.replace('.std','.png')) print 'DREW GLM OF', stdString except: exceptionCount += 1 print 'FAILED DRAWING', stdString try: # Run powerflow on the GLM. output = gridlabd.runInFilesystem(outGlm, keepFiles=False) with open(stdString.replace('.std','.json'),'w') as outFile: json.dump(output, outFile, indent=4) print 'RAN GRIDLAB ON', stdString except: exceptionCount += 1 print 'POWERFLOW FAILED', stdString except: print 'FAILED CONVERTING', stdString exceptionCount += 1 traceback.print_exc() print exceptionCount
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 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
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
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)
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
def runForeground(modelDir, inputDict): ''' Run the model in the foreground. WARNING: can take about a minute. ''' # Global vars, and load data from the model directory. print "STARTING TO RUN", modelDir try: startTime = datetime.datetime.now() if not os.path.isdir(modelDir): os.makedirs(modelDir) inputDict["created"] = str(startTime) feederName = inputDict.get('feederName1','feeder1') feederPath = pJoin(modelDir,feederName+'.omd') feederJson = json.load(open(feederPath)) tree = feederJson.get("tree",{}) attachments = feederJson.get("attachments",{}) allOutput = {} ''' Run CVR analysis. ''' # Reformate monthData and rates. rates = {k:float(inputDict[k]) for k in ["capitalCost", "omCost", "wholesaleEnergyCostPerKwh", "retailEnergyCostPerKwh", "peakDemandCostSpringPerKw", "peakDemandCostSummerPerKw", "peakDemandCostFallPerKw", "peakDemandCostWinterPerKw"]} # print "RATES", rates 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'} monthData = [] for i, x in enumerate(monthNames): monShort = x[0:3].lower() season = monthToSeason[x] histAvg = float(inputDict.get(monShort + "Avg", 0)) histPeak = float(inputDict.get(monShort + "Peak", 0)) monthData.append({"monthId":i, "monthName":x, "histAverage":histAvg, "histPeak":histPeak, "season":season}) # for row in monthData: # print row # Graph the SCADA data. fig = plt.figure(figsize=(10,6)) indices = [r['monthName'] for r in monthData] d1 = [r['histPeak']/(10**3) for r in monthData] d2 = [r['histAverage']/(10**3) for r in monthData] ticks = range(len(d1)) bar_peak = plt.bar(ticks,d1,color='gray') bar_avg = plt.bar(ticks,d2,color='dimgray') plt.legend([bar_peak[0],bar_avg[0]],['histPeak','histAverage'],bbox_to_anchor=(0., 1.015, 1., .102), loc=3, ncol=2, mode="expand", borderaxespad=0.1) plt.xticks([t+0.5 for t in ticks],indices) plt.ylabel('Mean and peak historical power consumptions (kW)') fig.autofmt_xdate() plt.savefig(pJoin(modelDir,"scadaChart.png")) allOutput["histPeak"] = d1 allOutput["histAverage"] = d2 allOutput["monthName"] = [name[0:3] for name in monthNames] # Graph feeder. fig = plt.figure(figsize=(10,10)) myGraph = feeder.treeToNxGraph(tree) feeder.latLonNxGraph(myGraph, neatoLayout=False) plt.savefig(pJoin(modelDir,"feederChart.png")) with open(pJoin(modelDir,"feederChart.png"),"rb") as inFile: allOutput["feederChart"] = inFile.read().encode("base64") # Get the load levels we need to test. allLoadLevels = [x.get('histPeak',0) for x in monthData] + [y.get('histAverage',0) for y in monthData] maxLev = _roundOne(max(allLoadLevels),'up') minLev = _roundOne(min(allLoadLevels),'down') tenLoadLevels = range(int(minLev),int(maxLev),int((maxLev-minLev)/10)) # Gather variables from the feeder. for key in tree.keys(): # Set clock to single timestep. if tree[key].get('clock','') == 'clock': tree[key] = {"timezone":"PST+8PDT", "stoptime":"'2013-01-01 00:00:00'", "starttime":"'2013-01-01 00:00:00'", "clock":"clock"} # Save swing node index. if tree[key].get('bustype','').lower() == 'swing': swingIndex = key swingName = tree[key].get('name') # Remove all includes. if tree[key].get('omftype','') == '#include': del key # Find the substation regulator and config. for key in tree: if tree[key].get('object','') == 'regulator' and tree[key].get('from','') == swingName: regIndex = key regConfName = tree[key]['configuration'] if not regConfName: regConfName = False for key in tree: if tree[key].get('name','') == regConfName: regConfIndex = key # Set substation regulator to manual operation. baselineTap = int(inputDict.get("baselineTap")) # GLOBAL VARIABLE FOR DEFAULT TAP POSITION tree[regConfIndex] = { 'name':tree[regConfIndex]['name'], 'object':'regulator_configuration', 'connect_type':'1', 'raise_taps':'10', 'lower_taps':'10', 'CT_phase':'ABC', 'PT_phase':'ABC', 'regulation':'0.10', #Yo, 0.10 means at tap_pos 10 we're 10% above 120V. 'Control':'MANUAL', 'control_level':'INDIVIDUAL', 'Type':'A', 'tap_pos_A':str(baselineTap), 'tap_pos_B':str(baselineTap), 'tap_pos_C':str(baselineTap) } # 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': tree[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': tree[swingIndex]['name'], 'property': 'voltage_A,voltage_B,voltage_C'}, {'object': 'recorder', 'file': 'ZsubstationBottom.csv', 'limit': '0', 'parent': tree[regIndex]['to'], 'property': 'voltage_A,voltage_B,voltage_C'} ] biggest = 1 + max([int(k) for k in tree.keys()]) for index, rec in enumerate(recorders): tree[biggest + index] = rec # Change constant PF loads to ZIP loads. (See evernote for rationale about 50/50 power/impedance mix.) blankZipModel = {'object':'triplex_load', 'name':'NAMEVARIABLE', 'base_power_12':'POWERVARIABLE', 'power_fraction_12': str(inputDict.get("p_percent")), 'impedance_fraction_12': str(inputDict.get("z_percent")), 'current_fraction_12': str(inputDict.get("i_percent")), 'power_pf_12': str(inputDict.get("power_factor")), #MAYBEFIX: we can probably get this PF data from the Milsoft loads. 'impedance_pf_12':str(inputDict.get("power_factor")), 'current_pf_12':str(inputDict.get("power_factor")), 'nominal_voltage':'120', 'phases':'PHASESVARIABLE', 'parent':'PARENTVARIABLE' } def powerClean(powerStr): ''' take 3339.39+1052.29j to 3339.39 ''' return powerStr[0:powerStr.find('+')] for key in tree: if tree[key].get('object','') == 'triplex_node': # Get existing variables. name = tree[key].get('name','') power = tree[key].get('power_12','') parent = tree[key].get('parent','') phases = tree[key].get('phases','') # Replace object and reintroduce variables. tree[key] = copy(blankZipModel) tree[key]['name'] = name tree[key]['base_power_12'] = powerClean(power) tree[key]['parent'] = parent tree[key]['phases'] = phases # Function to determine how low we can tap down in the CVR case: def loweringPotential(baseLine): ''' Given a baseline end of line voltage, how many more percent can we shave off the substation voltage? ''' ''' testsWePass = [122.0,118.0,200.0,110.0] ''' lower = int(math.floor((baseLine/114.0-1)*100)) - 1 # If lower is negative, we can't return it because we'd be undervolting beyond what baseline already was! if lower < 0: return baselineTap else: return baselineTap - lower # Run all the powerflows. powerflows = [] for doingCvr in [False, True]: # For each load level in the tenLoadLevels, run a powerflow with the load objects scaled to the level. for desiredLoad in tenLoadLevels: # Find the total load that was defined in Milsoft: loadList = [] for key in tree: if tree[key].get('object','') == 'triplex_load': loadList.append(tree[key].get('base_power_12','')) totalLoad = sum([float(x) for x in loadList]) # Rescale each triplex load: for key in tree: if tree[key].get('object','') == 'triplex_load': currentPow = float(tree[key]['base_power_12']) ratio = desiredLoad/totalLoad tree[key]['base_power_12'] = str(currentPow*ratio) # If we're doing CVR then lower the voltage. if doingCvr: # Find the minimum voltage we can tap down to: newTapPos = baselineTap for row in powerflows: if row.get('loadLevel','') == desiredLoad: newTapPos = loweringPotential(row.get('lowVoltage',114)) # Tap it down to there. # MAYBEFIX: do each phase separately because that's how it's done in the field... Oof. tree[regConfIndex]['tap_pos_A'] = str(newTapPos) tree[regConfIndex]['tap_pos_B'] = str(newTapPos) tree[regConfIndex]['tap_pos_C'] = str(newTapPos) # Run the model through gridlab and put outputs in the table. output = gridlabd.runInFilesystem(tree, attachments=attachments, keepFiles=True, workDir=modelDir) os.remove(pJoin(modelDir,"PID.txt")) p = output['Zregulator.csv']['power_in.real'][0] q = output['Zregulator.csv']['power_in.imag'][0] s = math.sqrt(p**2+q**2) lossTotal = 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)'][0] i = output[device]['sum(power_losses_' + letter + '.imag)'][0] lossTotal += math.sqrt(r**2 + i**2) ## Entire output: powerflows.append({ 'doingCvr':doingCvr, 'loadLevel':desiredLoad, 'realPower':p, 'powerFactor':p/s, 'losses':lossTotal, 'subVoltage': ( output['ZsubstationBottom.csv']['voltage_A'][0] + output['ZsubstationBottom.csv']['voltage_B'][0] + output['ZsubstationBottom.csv']['voltage_C'][0] )/3/60, 'lowVoltage':output['ZvoltageJiggle.csv']['min(voltage_12.mag)'][0]/2, 'highVoltage':output['ZvoltageJiggle.csv']['max(voltage_12.mag)'][0]/2 }) # For a given load level, find two points to interpolate on. def getInterpPoints(t): ''' Find the two points we can interpolate from. ''' ''' tests pass on [tenLoadLevels[0],tenLoadLevels[5]+499,tenLoadLevels[-1]-988] ''' loc = sorted(tenLoadLevels + [t]).index(t) if loc==0: return (tenLoadLevels[0],tenLoadLevels[1]) elif loc>len(tenLoadLevels)-2: return (tenLoadLevels[-2],tenLoadLevels[-1]) else: return (tenLoadLevels[loc-1],tenLoadLevels[loc+1]) # Calculate peak reduction. for row in monthData: peak = row['histPeak'] peakPoints = getInterpPoints(peak) peakTopBase = [x for x in powerflows if x.get('loadLevel','') == peakPoints[-1] and x.get('doingCvr','') == False][0] peakTopCvr = [x for x in powerflows if x.get('loadLevel','') == peakPoints[-1] and x.get('doingCvr','') == True][0] peakBottomBase = [x for x in powerflows if x.get('loadLevel','') == peakPoints[0] and x.get('doingCvr','') == False][0] peakBottomCvr = [x for x in powerflows if x.get('loadLevel','') == peakPoints[0] and x.get('doingCvr','') == True][0] # Linear interpolation so we aren't running umpteen million loadflows. x = (peakPoints[0],peakPoints[1]) y = (peakTopBase['realPower'] - peakTopCvr['realPower'], peakBottomBase['realPower'] - peakBottomCvr['realPower']) peakRed = y[0] + (y[1] - y[0]) * (peak - x[0]) / (x[1] - x[0]) row['peakReduction'] = peakRed # Calculate energy reduction and loss reduction based on average load. for row in monthData: avgEnergy = row['histAverage'] energyPoints = getInterpPoints(avgEnergy) avgTopBase = [x for x in powerflows if x.get('loadLevel','') == energyPoints[-1] and x.get('doingCvr','') == False][0] avgTopCvr = [x for x in powerflows if x.get('loadLevel','') == energyPoints[-1] and x.get('doingCvr','') == True][0] avgBottomBase = [x for x in powerflows if x.get('loadLevel','') == energyPoints[0] and x.get('doingCvr','') == False][0] avgBottomCvr = [x for x in powerflows if x.get('loadLevel','') == energyPoints[0] and x.get('doingCvr','') == True][0] # Linear interpolation so we aren't running umpteen million loadflows. x = (energyPoints[0], energyPoints[1]) y = (avgTopBase['realPower'] - avgTopCvr['realPower'], avgBottomBase['realPower'] - avgBottomCvr['realPower']) energyRed = y[0] + (y[1] - y[0]) * (avgEnergy - x[0]) / (x[1] - x[0]) row['energyReduction'] = energyRed lossY = (avgTopBase['losses'] - avgTopCvr['losses'], avgBottomBase['losses'] - avgBottomCvr['losses']) lossRed = lossY[0] + (lossY[1] - lossY[0]) * (avgEnergy - x[0]) / (x[1] - x[0]) row['lossReduction'] = lossRed # Multiply by dollars. for row in monthData: row['energyReductionDollars'] = row['energyReduction']/1000 * (rates['wholesaleEnergyCostPerKwh'] - rates['retailEnergyCostPerKwh']) row['peakReductionDollars'] = row['peakReduction']/1000 * rates['peakDemandCost' + row['season'] + 'PerKw'] row['lossReductionDollars'] = row['lossReduction']/1000 * rates['wholesaleEnergyCostPerKwh'] # Pretty output def plotTable(inData): fig = plt.figure(figsize=(10,5)) plt.axis('off') plt.tight_layout() plt.table(cellText=[row for row in inData[1:]], loc = 'center', rowLabels = range(len(inData)-1), colLabels = inData[0]) def dictalToMatrix(dictList): ''' Take our dictal format to a matrix. ''' matrix = [dictList[0].keys()] for row in dictList: matrix.append(row.values()) return matrix # Powerflow results. plotTable(dictalToMatrix(powerflows)) plt.savefig(pJoin(modelDir,"powerflowTable.png")) # Monetary results. ## To print partial money table monthDataMat = dictalToMatrix(monthData) dimX = len(monthDataMat) dimY = len(monthDataMat[0]) monthDataPart = [] for k in range (0,dimX): monthDatatemp = [] for m in range (4,dimY): monthDatatemp.append(monthDataMat[k][m]) monthDataPart.append(monthDatatemp) plotTable(monthDataPart) plt.savefig(pJoin(modelDir,"moneyTable.png")) allOutput["monthDataMat"] = dictalToMatrix(monthData) allOutput["monthDataPart"] = monthDataPart # Graph the money data. fig = plt.figure(figsize=(10,8)) indices = [r['monthName'] for r in monthData] d1 = [r['energyReductionDollars'] for r in monthData] d2 = [r['lossReductionDollars'] for r in monthData] d3 = [r['peakReductionDollars'] for r in monthData] ticks = range(len(d1)) bar_erd = plt.bar(ticks,d1,color='red') bar_lrd = plt.bar(ticks,d2,color='green') bar_prd = plt.bar(ticks,d3,color='blue',yerr=d2) plt.legend([bar_prd[0], bar_lrd[0], bar_erd[0]], ['peakReductionDollars','lossReductionDollars','energyReductionDollars'],bbox_to_anchor=(0., 1.015, 1., .102), loc=3, ncol=2, mode="expand", borderaxespad=0.1) plt.xticks([t+0.5 for t in ticks],indices) plt.ylabel('Utility Savings ($)') plt.tight_layout(5.5,1.3,1.2) fig.autofmt_xdate() plt.savefig(pJoin(modelDir,"spendChart.png")) allOutput["energyReductionDollars"] = d1 allOutput["lossReductionDollars"] = d2 allOutput["peakReductionDollars"] = d3 # Graph the cumulative savings. fig = plt.figure(figsize=(10,5)) annualSavings = sum(d1) + sum(d2) + sum(d3) annualSave = lambda x:(annualSavings - rates['omCost']) * x - rates['capitalCost'] simplePayback = rates['capitalCost']/(annualSavings - rates['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")) allOutput["annualSave"] = [annualSave(x) for x in range(31)] # 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) # Write output file. 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: # 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)
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
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
def _tests(Network, Equipment, keepFiles=True): import os, json, traceback, shutil from solvers import gridlabd from matplotlib import pyplot as plt import feeder exceptionCount = 0 try: #db_network = os.path.abspath('./uploads/IEEE13.mdb') #db_equipment = os.path.abspath('./uploads/IEEE13.mdb') prefix = str(Path("testPEC.py").resolve()).strip('scratch\cymeToGridlabTests\testPEC.py') + "\uploads\\" db_network = "C" + prefix + Network db_equipment = "C" + prefix + Equipment id_feeder = '650' conductors = prefix + "conductor_data.csv" #print "dbnet", db_network #print "eqnet", db_equipment #print "conductors", conductors #cyme_base, x, y = convertCymeModel(db_network, db_equipment, id_feeder, conductors) cyme_base, x, y = convertCymeModel(str(db_network), str(db_equipment), test=True, type=2, feeder_id='CV160') feeder.attachRecorders(cyme_base, "TriplexLosses", None, None) feeder.attachRecorders(cyme_base, "TransformerLosses", None, None) glmString = feeder.sortedWrite(cyme_base) feederglm = "C:\Users\Asus\Documents\GitHub\omf\omf\uploads\PEC.glm" #print "feeederglm", feederglm gfile = open(feederglm, 'w') gfile.write(glmString) gfile.close() #print 'WROTE GLM FOR' outPrefix = "C:\Users\Asus\Documents\GitHub\omf\omf\scratch\cymeToGridlabTests\\" try: os.mkdir(outPrefix) except: pass # Directory already there. '''Attempt to graph''' try: # Draw the GLM. print "trying to graph" myGraph = feeder.treeToNxGraph(cyme_base) feeder.latLonNxGraph(myGraph, neatoLayout=False) plt.savefig(outPrefix + "PEC.png") print "outprefix", outPrefix + "PEC.png" print 'DREW GLM OF' except: exceptionCount += 1 print 'FAILED DRAWING' try: # Run powerflow on the GLM. output = gridlabd.runInFilesystem(glmString, keepFiles=False) with open(outPrefix + "PEC.JSON",'w') as outFile: json.dump(output, outFile, indent=4) print 'RAN GRIDLAB ON\n' except: exceptionCount += 1 print 'POWERFLOW FAILED' except: print 'FAILED CONVERTING' exceptionCount += 1 traceback.print_exc() if not keepFiles: shutil.rmtree(outPrefix) return exceptionCount '''db_network = os.path.abspath('./uploads/PasoRobles11cymsectiondevice[device]['phases']08.mdb')
def voltPlot(tree, workDir=None, neatoLayout=False): ''' Draw a color-coded map of the voltage drop on a feeder. Returns a matplotlib object. ''' # Get rid of schedules and climate: for key in tree.keys(): if tree[key].get("argument", "") == "\"schedules.glm\"" or tree[key].get( "tmyfile", "") != "": del tree[key] # Make sure we have a voltDump: def safeInt(x): try: return int(x) except: return 0 biggestKey = max([safeInt(x) for x in tree.keys()]) tree[str(biggestKey * 10)] = { "object": "voltdump", "filename": "voltDump.csv" } # Run Gridlab. if not workDir: workDir = tempfile.mkdtemp() print "gridlabD runInFilesystem with no specified workDir. Working in", workDir gridlabOut = gridlabd.runInFilesystem(tree, attachments=[], workDir=workDir) with open(pJoin(workDir, 'voltDump.csv'), 'r') as dumpFile: reader = csv.reader(dumpFile) reader.next() # Burn the header. keys = reader.next() voltTable = [] for row in reader: rowDict = {} for pos, key in enumerate(keys): rowDict[key] = row[pos] voltTable.append(rowDict) # Calculate average node voltage deviation. First, helper functions. def pythag(x, y): ''' For right triangle with sides a and b, return the hypotenuse. ''' return math.sqrt(x**2 + y**2) def digits(x): ''' Returns number of digits before the decimal in the float x. ''' return math.ceil(math.log10(x + 1)) def avg(l): ''' Average of a list of ints or floats. ''' return sum(l) / len(l) # Detect the feeder nominal voltage: for key in tree: ob = tree[key] if type(ob) == dict and ob.get('bustype', '') == 'SWING': feedVoltage = float(ob.get('nominal_voltage', 1)) # Tot it all up. nodeVolts = {} for row in voltTable: allVolts = [] for phase in ['A', 'B', 'C']: phaseVolt = pythag(float(row['volt' + phase + '_real']), float(row['volt' + phase + '_imag'])) if phaseVolt != 0.0: if digits(phaseVolt) > 3: # Normalize to 120 V standard phaseVolt = phaseVolt * (120 / feedVoltage) allVolts.append(phaseVolt) nodeVolts[row.get('node_name', '')] = avg(allVolts) # Color nodes by VOLTAGE. fGraph = feeder.treeToNxGraph(tree) voltChart = plt.figure(figsize=(10, 10)) plt.axes(frameon=0) plt.axis('off') if neatoLayout: # HACK: work on a new graph without attributes because graphViz tries to read attrs. cleanG = nx.Graph(fGraph.edges()) cleanG.add_nodes_from(fGraph) positions = nx.graphviz_layout(cleanG, prog='neato') else: positions = {n: fGraph.node[n].get('pos', (0, 0)) for n in fGraph} edgeIm = nx.draw_networkx_edges(fGraph, positions) nodeIm = nx.draw_networkx_nodes( fGraph, pos=positions, node_color=[nodeVolts.get(n, 0) for n in fGraph.nodes()], linewidths=0, node_size=30, cmap=plt.cm.jet) plt.sci(nodeIm) plt.clim(110, 130) plt.colorbar() return voltChart
def _tests(makeKey=False, runGridlabD=True, showGDLABResults=False, cleanUp=True): '''Get and encrypt a .std/.seq files to a .json. cleanUp removes the unencrypted .glm and .json. ''' # Inputs. user = "******" workDir = pJoin(os.getcwd()) try: os.mkdir(pJoin(os.getcwd(),'encryptedFiles')) except: pass if makeKey: genKey(workDir, user) print "Made a new key for user:"******"Read key for user:"******"Working on:", stdString+",",seqString with open(pJoin("inFiles",stdString),'r') as stdFile, open(pJoin("inFiles",seqString),'r') as seqFile: stdContents, seqContents = stdFile.read(), seqFile.read() # print "First few lines before encryption:\n", stdContents[:100] encData = encryptData(stdContents, key) with open(pJoin(workDir, "encryptedFiles", "Encrypted_"+stdString),"w+") as encFile: encFile.write(encData) encData = encryptData(seqContents, key) with open(pJoin(workDir, "encryptedFiles", "Encrypted_"+seqString),"w+") as encFile: encFile.write(encData) # print "First few lines after enc:\n", encData[:100] # Read and decrypt to convert to a .glm. with open(pJoin(workDir, "encryptedFiles", "Encrypted_"+stdString),'r') as inFile: encStdContents = inFile.read() with open(pJoin(workDir, "encryptedFiles", "Encrypted_"+seqString),'r') as inFile2: encSeqContents = inFile2.read() print "\nCreated encrypted files:", "Encrypted_"+stdString+",", "Encrypted_"+seqString # Decrypt. decStdContents = decryptData(encStdContents,key) decSeqContents = decryptData(encSeqContents,key) # print "First few lines after dec:\n", decStdContents[:100] # Convert to .glm. def runMilConvert(stdContents, seqContents): myFeed, xScale, yScale = omf.milToGridlab.convert(stdContents,seqContents) with open(pJoin(workDir,stdString.replace('.std','.glm')),'w') as outFile: outFile.write(omf.feeder.sortedWrite(myFeed)) myGraph = omf.feeder.treeToNxGraph(myFeed) omf.feeder.latLonNxGraph(myGraph, neatoLayout=False) plt.savefig(pJoin(workDir,stdString.replace('.std','.png'))) plt.close() if not os.path.isfile(pJoin(workDir,stdString.replace('.std','.glm'))): runMilConvert(decStdContents, decSeqContents) print "Converted std/seq to glm." # Convert converted .glm to encrypted glm. with open(pJoin(workDir,stdString.replace('.std','.glm')),'r') as inGLM: glmContents = inGLM.read() encData = encryptData(glmContents, key) with open(pJoin(workDir, "encryptedFiles","Encrypted_"+stdString.replace('.std','.glm')),'w') as encFile: encFile.write(encData) print "Encrypted glm file:", stdString.replace('.std','.glm') # Decrypt .glm, convert to .json. with open(pJoin(workDir, "encryptedFiles", "Encrypted_"+stdString.replace('.std','.glm')),'r') as encFile: encOutGlm = encFile.read() outGlm = decryptData(encOutGlm,key) newFeeder = gridlabImport(workDir, stdString.strip('.std'), outGlm) # Run gridlabD on decrypted GLM. if runGridlabD: output = gridlabd.runInFilesystem(newFeeder['tree'], attachments=testAttachments, keepFiles=False) if showGDLABResults: print "[STDERR]\n", (output['stderr']) print "[STDOUT]\n", (output['stdout']) print 'RAN GRIDLAB ON', stdString # Convert JSON to encrypted json. with open(pJoin(workDir,stdString.replace('.std','.json')),'r') as encFile: decJSON = encFile.read() encData = encryptData(decJSON, key) with open(pJoin(workDir,"encryptedFiles","Encrypted_"+stdString.replace('.std','.json')),'w') as encFile: encFile.write(encData) print "Encrypted JSON file:", stdString.replace('.std','.json') # Clean up unencrypted .glm and .json. if cleanUp: try: os.remove(pJoin(workDir,stdString.replace('.std','.glm'))) print "Removed unencrypted file:", stdString.replace('.std','.glm') except: pass try: os.remove(pJoin(workDir,stdString.replace('.std','.json'))) print "Removed unencrypted file:", stdString.replace('.std','.json') except: pass print "\nDone with encrypting all test files." except: print "Failed to encrypt", stdString, seqString exceptionCount += 1 traceback.print_exc() return exceptionCount
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
def _tests(Network, Equipment, keepFiles=True): import os, json, traceback, shutil from solvers import gridlabd from matplotlib import pyplot as plt import feeder exceptionCount = 0 try: #db_network = os.path.abspath('./uploads/IEEE13.mdb') #db_equipment = os.path.abspath('./uploads/IEEE13.mdb') prefix = str(Path("testPEC.py").resolve()).strip( 'scratch\cymeToGridlabTests\testPEC.py') + "\uploads\\" db_network = "C" + prefix + Network db_equipment = "C" + prefix + Equipment id_feeder = '650' conductors = prefix + "conductor_data.csv" #print "dbnet", db_network #print "eqnet", db_equipment #print "conductors", conductors #cyme_base, x, y = convertCymeModel(db_network, db_equipment, id_feeder, conductors) cyme_base, x, y = convertCymeModel(str(db_network), str(db_equipment), test=True, type=2, feeder_id='CV160') feeder.attachRecorders(cyme_base, "TriplexLosses", None, None) feeder.attachRecorders(cyme_base, "TransformerLosses", None, None) glmString = feeder.sortedWrite(cyme_base) feederglm = "C:\Users\Asus\Documents\GitHub\omf\omf\uploads\PEC.glm" #print "feeederglm", feederglm gfile = open(feederglm, 'w') gfile.write(glmString) gfile.close() #print 'WROTE GLM FOR' outPrefix = "C:\Users\Asus\Documents\GitHub\omf\omf\scratch\cymeToGridlabTests\\" try: os.mkdir(outPrefix) except: pass # Directory already there. '''Attempt to graph''' try: # Draw the GLM. print "trying to graph" myGraph = feeder.treeToNxGraph(cyme_base) feeder.latLonNxGraph(myGraph, neatoLayout=False) plt.savefig(outPrefix + "PEC.png") print "outprefix", outPrefix + "PEC.png" print 'DREW GLM OF' except: exceptionCount += 1 print 'FAILED DRAWING' try: # Run powerflow on the GLM. output = gridlabd.runInFilesystem(glmString, keepFiles=False) with open(outPrefix + "PEC.JSON", 'w') as outFile: json.dump(output, outFile, indent=4) print 'RAN GRIDLAB ON\n' except: exceptionCount += 1 print 'POWERFLOW FAILED' except: print 'FAILED CONVERTING' exceptionCount += 1 traceback.print_exc() if not keepFiles: shutil.rmtree(outPrefix) return exceptionCount '''db_network = os.path.abspath('./uploads/PasoRobles11cymsectiondevice[device]['phases']08.mdb')
'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 try: os.remove('./Orville Tree Pond Calibrated With Weather.json') except: pass with open('./Orville Tree Pond Calibrated With Weather.json', 'w') as outFile:
def voltPlot(tree, workDir=None, neatoLayout=False): ''' Draw a color-coded map of the voltage drop on a feeder. Returns a matplotlib object. ''' # Get rid of schedules and climate: for key in tree.keys(): if tree[key].get("argument","") == "\"schedules.glm\"" or tree[key].get("tmyfile","") != "": del tree[key] # Make sure we have a voltDump: def safeInt(x): try: return int(x) except: return 0 biggestKey = max([safeInt(x) for x in tree.keys()]) tree[str(biggestKey*10)] = {"object":"voltdump","filename":"voltDump.csv"} # Run Gridlab. if not workDir: workDir = tempfile.mkdtemp() print "gridlabD runInFilesystem with no specified workDir. Working in", workDir gridlabOut = gridlabd.runInFilesystem(tree, attachments=[], workDir=workDir) with open(pJoin(workDir,'voltDump.csv'),'r') as dumpFile: reader = csv.reader(dumpFile) reader.next() # Burn the header. keys = reader.next() voltTable = [] for row in reader: rowDict = {} for pos,key in enumerate(keys): rowDict[key] = row[pos] voltTable.append(rowDict) # Calculate average node voltage deviation. First, helper functions. def pythag(x,y): ''' For right triangle with sides a and b, return the hypotenuse. ''' return math.sqrt(x**2+y**2) def digits(x): ''' Returns number of digits before the decimal in the float x. ''' return math.ceil(math.log10(x+1)) def avg(l): ''' Average of a list of ints or floats. ''' return sum(l)/len(l) # Detect the feeder nominal voltage: for key in tree: ob = tree[key] if type(ob)==dict and ob.get('bustype','')=='SWING': feedVoltage = float(ob.get('nominal_voltage',1)) # Tot it all up. nodeVolts = {} for row in voltTable: allVolts = [] for phase in ['A','B','C']: phaseVolt = pythag(float(row['volt'+phase+'_real']), float(row['volt'+phase+'_imag'])) if phaseVolt != 0.0: if digits(phaseVolt)>3: # Normalize to 120 V standard phaseVolt = phaseVolt*(120/feedVoltage) allVolts.append(phaseVolt) nodeVolts[row.get('node_name','')] = avg(allVolts) # Color nodes by VOLTAGE. fGraph = feeder.treeToNxGraph(tree) voltChart = plt.figure(figsize=(10,10)) plt.axes(frameon = 0) plt.axis('off') if neatoLayout: # HACK: work on a new graph without attributes because graphViz tries to read attrs. cleanG = nx.Graph(fGraph.edges()) cleanG.add_nodes_from(fGraph) positions = nx.graphviz_layout(cleanG, prog='neato') else: positions = {n:fGraph.node[n].get('pos',(0,0)) for n in fGraph} edgeIm = nx.draw_networkx_edges(fGraph, positions) nodeIm = nx.draw_networkx_nodes(fGraph, pos = positions, node_color = [nodeVolts.get(n,0) for n in fGraph.nodes()], linewidths = 0, node_size = 30, cmap = plt.cm.jet) plt.sci(nodeIm) plt.clim(110,130) plt.colorbar() return voltChart
def runForeground(modelDir, inputDict): ''' Run the model in the foreground. WARNING: can take about a minute. ''' # Global vars, and load data from the model directory. print "STARTING TO RUN", modelDir try: startTime = datetime.datetime.now() if not os.path.isdir(modelDir): os.makedirs(modelDir) inputDict["created"] = str(startTime) feederPath = pJoin(__metaModel__._omfDir,"data", "Feeder", inputDict["feederName"].split("___")[0], inputDict["feederName"].split("___")[1]+'.json') feederJson = json.load(open(feederPath)) tree = feederJson.get("tree",{}) attachments = feederJson.get("attachments",{}) allOutput = {} ''' Run CVR analysis. ''' # Reformate monthData and rates. rates = {k:float(inputDict[k]) for k in ["capitalCost", "omCost", "wholesaleEnergyCostPerKwh", "retailEnergyCostPerKwh", "peakDemandCostSpringPerKw", "peakDemandCostSummerPerKw", "peakDemandCostFallPerKw", "peakDemandCostWinterPerKw"]} # print "RATES", rates 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'} monthData = [] for i, x in enumerate(monthNames): monShort = x[0:3].lower() season = monthToSeason[x] histAvg = float(inputDict.get(monShort + "Avg", 0)) histPeak = float(inputDict.get(monShort + "Peak", 0)) monthData.append({"monthId":i, "monthName":x, "histAverage":histAvg, "histPeak":histPeak, "season":season}) # for row in monthData: # print row # Graph the SCADA data. fig = plt.figure(figsize=(10,6)) indices = [r['monthName'] for r in monthData] d1 = [r['histPeak']/(10**3) for r in monthData] d2 = [r['histAverage']/(10**3) for r in monthData] ticks = range(len(d1)) bar_peak = plt.bar(ticks,d1,color='gray') bar_avg = plt.bar(ticks,d2,color='dimgray') plt.legend([bar_peak[0],bar_avg[0]],['histPeak','histAverage'],bbox_to_anchor=(0., 1.015, 1., .102), loc=3, ncol=2, mode="expand", borderaxespad=0.1) plt.xticks([t+0.5 for t in ticks],indices) plt.ylabel('Mean and peak historical power consumptions (kW)') fig.autofmt_xdate() plt.savefig(pJoin(modelDir,"scadaChart.png")) allOutput["histPeak"] = d1 allOutput["histAverage"] = d2 allOutput["monthName"] = [name[0:3] for name in monthNames] # Graph feeder. fig = plt.figure(figsize=(10,10)) myGraph = feeder.treeToNxGraph(tree) feeder.latLonNxGraph(myGraph, neatoLayout=False) plt.savefig(pJoin(modelDir,"feederChart.png")) with open(pJoin(modelDir,"feederChart.png"),"rb") as inFile: allOutput["feederChart"] = inFile.read().encode("base64") # Get the load levels we need to test. allLoadLevels = [x.get('histPeak',0) for x in monthData] + [y.get('histAverage',0) for y in monthData] maxLev = _roundOne(max(allLoadLevels),'up') minLev = _roundOne(min(allLoadLevels),'down') tenLoadLevels = range(int(minLev),int(maxLev),int((maxLev-minLev)/10)) # Gather variables from the feeder. for key in tree.keys(): # Set clock to single timestep. if tree[key].get('clock','') == 'clock': tree[key] = {"timezone":"PST+8PDT", "stoptime":"'2013-01-01 00:00:00'", "starttime":"'2013-01-01 00:00:00'", "clock":"clock"} # Save swing node index. if tree[key].get('bustype','').lower() == 'swing': swingIndex = key swingName = tree[key].get('name') # Remove all includes. if tree[key].get('omftype','') == '#include': del key # Find the substation regulator and config. for key in tree: if tree[key].get('object','') == 'regulator' and tree[key].get('from','') == swingName: regIndex = key regConfName = tree[key]['configuration'] if not regConfName: regConfName = False for key in tree: if tree[key].get('name','') == regConfName: regConfIndex = key # Set substation regulator to manual operation. baselineTap = int(inputDict.get("baselineTap")) # GLOBAL VARIABLE FOR DEFAULT TAP POSITION tree[regConfIndex] = { 'name':tree[regConfIndex]['name'], 'object':'regulator_configuration', 'connect_type':'1', 'raise_taps':'10', 'lower_taps':'10', 'CT_phase':'ABC', 'PT_phase':'ABC', 'regulation':'0.10', #Yo, 0.10 means at tap_pos 10 we're 10% above 120V. 'Control':'MANUAL', 'control_level':'INDIVIDUAL', 'Type':'A', 'tap_pos_A':str(baselineTap), 'tap_pos_B':str(baselineTap), 'tap_pos_C':str(baselineTap) } # 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': tree[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': tree[swingIndex]['name'], 'property': 'voltage_A,voltage_B,voltage_C'}, {'object': 'recorder', 'file': 'ZsubstationBottom.csv', 'limit': '0', 'parent': tree[regIndex]['to'], 'property': 'voltage_A,voltage_B,voltage_C'} ] biggest = 1 + max([int(k) for k in tree.keys()]) for index, rec in enumerate(recorders): tree[biggest + index] = rec # Change constant PF loads to ZIP loads. (See evernote for rationale about 50/50 power/impedance mix.) blankZipModel = {'object':'triplex_load', 'name':'NAMEVARIABLE', 'base_power_12':'POWERVARIABLE', 'power_fraction_12': str(inputDict.get("p_percent")), 'impedance_fraction_12': str(inputDict.get("z_percent")), 'current_fraction_12': str(inputDict.get("i_percent")), 'power_pf_12': str(inputDict.get("power_factor")), #MAYBEFIX: we can probably get this PF data from the Milsoft loads. 'impedance_pf_12':str(inputDict.get("power_factor")), 'current_pf_12':str(inputDict.get("power_factor")), 'nominal_voltage':'120', 'phases':'PHASESVARIABLE', 'parent':'PARENTVARIABLE' } def powerClean(powerStr): ''' take 3339.39+1052.29j to 3339.39 ''' return powerStr[0:powerStr.find('+')] for key in tree: if tree[key].get('object','') == 'triplex_node': # Get existing variables. name = tree[key].get('name','') power = tree[key].get('power_12','') parent = tree[key].get('parent','') phases = tree[key].get('phases','') # Replace object and reintroduce variables. tree[key] = copy(blankZipModel) tree[key]['name'] = name tree[key]['base_power_12'] = powerClean(power) tree[key]['parent'] = parent tree[key]['phases'] = phases # Function to determine how low we can tap down in the CVR case: def loweringPotential(baseLine): ''' Given a baseline end of line voltage, how many more percent can we shave off the substation voltage? ''' ''' testsWePass = [122.0,118.0,200.0,110.0] ''' lower = int(math.floor((baseLine/114.0-1)*100)) - 1 # If lower is negative, we can't return it because we'd be undervolting beyond what baseline already was! if lower < 0: return baselineTap else: return baselineTap - lower # Run all the powerflows. powerflows = [] for doingCvr in [False, True]: # For each load level in the tenLoadLevels, run a powerflow with the load objects scaled to the level. for desiredLoad in tenLoadLevels: # Find the total load that was defined in Milsoft: loadList = [] for key in tree: if tree[key].get('object','') == 'triplex_load': loadList.append(tree[key].get('base_power_12','')) totalLoad = sum([float(x) for x in loadList]) # Rescale each triplex load: for key in tree: if tree[key].get('object','') == 'triplex_load': currentPow = float(tree[key]['base_power_12']) ratio = desiredLoad/totalLoad tree[key]['base_power_12'] = str(currentPow*ratio) # If we're doing CVR then lower the voltage. if doingCvr: # Find the minimum voltage we can tap down to: newTapPos = baselineTap for row in powerflows: if row.get('loadLevel','') == desiredLoad: newTapPos = loweringPotential(row.get('lowVoltage',114)) # Tap it down to there. # MAYBEFIX: do each phase separately because that's how it's done in the field... Oof. tree[regConfIndex]['tap_pos_A'] = str(newTapPos) tree[regConfIndex]['tap_pos_B'] = str(newTapPos) tree[regConfIndex]['tap_pos_C'] = str(newTapPos) # Run the model through gridlab and put outputs in the table. output = gridlabd.runInFilesystem(tree, attachments=attachments, keepFiles=True, workDir=modelDir) os.remove(pJoin(modelDir,"PID.txt")) p = output['Zregulator.csv']['power_in.real'][0] q = output['Zregulator.csv']['power_in.imag'][0] s = math.sqrt(p**2+q**2) lossTotal = 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)'][0] i = output[device]['sum(power_losses_' + letter + '.imag)'][0] lossTotal += math.sqrt(r**2 + i**2) ## Entire output: powerflows.append({ 'doingCvr':doingCvr, 'loadLevel':desiredLoad, 'realPower':p, 'powerFactor':p/s, 'losses':lossTotal, 'subVoltage': ( output['ZsubstationBottom.csv']['voltage_A'][0] + output['ZsubstationBottom.csv']['voltage_B'][0] + output['ZsubstationBottom.csv']['voltage_C'][0] )/3/60, 'lowVoltage':output['ZvoltageJiggle.csv']['min(voltage_12.mag)'][0]/2, 'highVoltage':output['ZvoltageJiggle.csv']['max(voltage_12.mag)'][0]/2 }) # For a given load level, find two points to interpolate on. def getInterpPoints(t): ''' Find the two points we can interpolate from. ''' ''' tests pass on [tenLoadLevels[0],tenLoadLevels[5]+499,tenLoadLevels[-1]-988] ''' loc = sorted(tenLoadLevels + [t]).index(t) if loc==0: return (tenLoadLevels[0],tenLoadLevels[1]) elif loc>len(tenLoadLevels)-2: return (tenLoadLevels[-2],tenLoadLevels[-1]) else: return (tenLoadLevels[loc-1],tenLoadLevels[loc+1]) # Calculate peak reduction. for row in monthData: peak = row['histPeak'] peakPoints = getInterpPoints(peak) peakTopBase = [x for x in powerflows if x.get('loadLevel','') == peakPoints[-1] and x.get('doingCvr','') == False][0] peakTopCvr = [x for x in powerflows if x.get('loadLevel','') == peakPoints[-1] and x.get('doingCvr','') == True][0] peakBottomBase = [x for x in powerflows if x.get('loadLevel','') == peakPoints[0] and x.get('doingCvr','') == False][0] peakBottomCvr = [x for x in powerflows if x.get('loadLevel','') == peakPoints[0] and x.get('doingCvr','') == True][0] # Linear interpolation so we aren't running umpteen million loadflows. x = (peakPoints[0],peakPoints[1]) y = (peakTopBase['realPower'] - peakTopCvr['realPower'], peakBottomBase['realPower'] - peakBottomCvr['realPower']) peakRed = y[0] + (y[1] - y[0]) * (peak - x[0]) / (x[1] - x[0]) row['peakReduction'] = peakRed # Calculate energy reduction and loss reduction based on average load. for row in monthData: avgEnergy = row['histAverage'] energyPoints = getInterpPoints(avgEnergy) avgTopBase = [x for x in powerflows if x.get('loadLevel','') == energyPoints[-1] and x.get('doingCvr','') == False][0] avgTopCvr = [x for x in powerflows if x.get('loadLevel','') == energyPoints[-1] and x.get('doingCvr','') == True][0] avgBottomBase = [x for x in powerflows if x.get('loadLevel','') == energyPoints[0] and x.get('doingCvr','') == False][0] avgBottomCvr = [x for x in powerflows if x.get('loadLevel','') == energyPoints[0] and x.get('doingCvr','') == True][0] # Linear interpolation so we aren't running umpteen million loadflows. x = (energyPoints[0], energyPoints[1]) y = (avgTopBase['realPower'] - avgTopCvr['realPower'], avgBottomBase['realPower'] - avgBottomCvr['realPower']) energyRed = y[0] + (y[1] - y[0]) * (avgEnergy - x[0]) / (x[1] - x[0]) row['energyReduction'] = energyRed lossY = (avgTopBase['losses'] - avgTopCvr['losses'], avgBottomBase['losses'] - avgBottomCvr['losses']) lossRed = lossY[0] + (lossY[1] - lossY[0]) * (avgEnergy - x[0]) / (x[1] - x[0]) row['lossReduction'] = lossRed # Multiply by dollars. for row in monthData: row['energyReductionDollars'] = row['energyReduction']/1000 * (rates['wholesaleEnergyCostPerKwh'] - rates['retailEnergyCostPerKwh']) row['peakReductionDollars'] = row['peakReduction']/1000 * rates['peakDemandCost' + row['season'] + 'PerKw'] row['lossReductionDollars'] = row['lossReduction']/1000 * rates['wholesaleEnergyCostPerKwh'] # Pretty output def plotTable(inData): fig = plt.figure(figsize=(10,5)) plt.axis('off') plt.tight_layout() plt.table(cellText=[row for row in inData[1:]], loc = 'center', rowLabels = range(len(inData)-1), colLabels = inData[0]) def dictalToMatrix(dictList): ''' Take our dictal format to a matrix. ''' matrix = [dictList[0].keys()] for row in dictList: matrix.append(row.values()) return matrix # Powerflow results. plotTable(dictalToMatrix(powerflows)) plt.savefig(pJoin(modelDir,"powerflowTable.png")) # Monetary results. ## To print partial money table monthDataMat = dictalToMatrix(monthData) dimX = len(monthDataMat) dimY = len(monthDataMat[0]) monthDataPart = [] for k in range (0,dimX): monthDatatemp = [] for m in range (4,dimY): monthDatatemp.append(monthDataMat[k][m]) monthDataPart.append(monthDatatemp) plotTable(monthDataPart) plt.savefig(pJoin(modelDir,"moneyTable.png")) allOutput["monthDataMat"] = dictalToMatrix(monthData) allOutput["monthDataPart"] = monthDataPart # Graph the money data. fig = plt.figure(figsize=(10,8)) indices = [r['monthName'] for r in monthData] d1 = [r['energyReductionDollars'] for r in monthData] d2 = [r['lossReductionDollars'] for r in monthData] d3 = [r['peakReductionDollars'] for r in monthData] ticks = range(len(d1)) bar_erd = plt.bar(ticks,d1,color='red') bar_lrd = plt.bar(ticks,d2,color='green') bar_prd = plt.bar(ticks,d3,color='blue',yerr=d2) plt.legend([bar_prd[0], bar_lrd[0], bar_erd[0]], ['peakReductionDollars','lossReductionDollars','energyReductionDollars'],bbox_to_anchor=(0., 1.015, 1., .102), loc=3, ncol=2, mode="expand", borderaxespad=0.1) plt.xticks([t+0.5 for t in ticks],indices) plt.ylabel('Utility Savings ($)') plt.tight_layout(5.5,1.3,1.2) fig.autofmt_xdate() plt.savefig(pJoin(modelDir,"spendChart.png")) allOutput["energyReductionDollars"] = d1 allOutput["lossReductionDollars"] = d2 allOutput["peakReductionDollars"] = d3 # Graph the cumulative savings. fig = plt.figure(figsize=(10,5)) annualSavings = sum(d1) + sum(d2) + sum(d3) annualSave = lambda x:(annualSavings - rates['omCost']) * x - rates['capitalCost'] simplePayback = rates['capitalCost']/(annualSavings - rates['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")) allOutput["annualSave"] = [annualSave(x) for x in range(31)] # 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) # Write output file. 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: # 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)
def _tests(makeKey=False, runGridlabD=True, showGDLABResults=False, cleanUp=True): '''Get and encrypt a .std/.seq files to a .json. cleanUp removes the unencrypted .glm and .json. ''' # Inputs. user = "******" workDir = pJoin(os.getcwd()) try: os.mkdir(pJoin(os.getcwd(),'encryptedFiles')) except: pass if makeKey: genKey(workDir, user) print "Made a new key for user:"******"Read key for user:"******"Working on:", stdString+",",seqString with open(pJoin("../../","uploads",stdString),'r') as stdFile, open(pJoin("../../","uploads",seqString),'r') as seqFile: stdContents, seqContents = stdFile.read(), seqFile.read() # print "First few lines before encryption:\n", stdContents[:100] encData = encryptData(stdContents, key) with open(pJoin(workDir, "encryptedFiles", "Encrypted_"+stdString),"w+") as encFile: encFile.write(encData) encData = encryptData(seqContents, key) with open(pJoin(workDir, "encryptedFiles", "Encrypted_"+seqString),"w+") as encFile: encFile.write(encData) # print "First few lines after enc:\n", encData[:100] # Read and decrypt to convert to a .glm. with open(pJoin(workDir, "encryptedFiles", "Encrypted_"+stdString),'r') as inFile: encStdContents = inFile.read() with open(pJoin(workDir, "encryptedFiles", "Encrypted_"+seqString),'r') as inFile2: encSeqContents = inFile2.read() print "\nCreated encrypted files:", "Encrypted_"+stdString+",", "Encrypted_"+seqString # Decrypt. decStdContents = decryptData(encStdContents,key) decSeqContents = decryptData(encSeqContents,key) # print "First few lines after dec:\n", decStdContents[:100] # Convert to .glm. def runMilConvert(stdContents, seqContents): myFeed, xScale, yScale = omf.milToGridlab.convert(stdContents,seqContents) with open(pJoin(workDir,stdString.replace('.std','.glm')),'w') as outFile: outFile.write(omf.feeder.sortedWrite(myFeed)) myGraph = omf.feeder.treeToNxGraph(myFeed) omf.feeder.latLonNxGraph(myGraph, neatoLayout=False) plt.savefig(pJoin(workDir,stdString.replace('.std','.png'))) plt.close() if not os.path.isfile(pJoin(workDir,stdString.replace('.std','.glm'))): runMilConvert(decStdContents, decSeqContents) print "Converted std/seq to glm." # Convert converted .glm to encrypted glm. with open(pJoin(workDir,stdString.replace('.std','.glm')),'r') as inGLM: glmContents = inGLM.read() encData = encryptData(glmContents, key) with open(pJoin(workDir, "encryptedFiles","Encrypted_"+stdString.replace('.std','.glm')),'w') as encFile: encFile.write(encData) print "Encrypted glm file:", stdString.replace('.std','.glm') # Decrypt .glm, convert to .json. with open(pJoin(workDir, "encryptedFiles", "Encrypted_"+stdString.replace('.std','.glm')),'r') as encFile: encOutGlm = encFile.read() outGlm = decryptData(encOutGlm,key) newFeeder = gridlabImport(workDir, stdString.strip('.std'), outGlm) # Run gridlabD on decrypted GLM. if runGridlabD: output = gridlabd.runInFilesystem(newFeeder['tree'], attachments=testAttachments, keepFiles=False) if showGDLABResults: print "[STDERR]\n", (output['stderr']) print "[STDOUT]\n", (output['stdout']) print 'RAN GRIDLAB ON', stdString # Convert JSON to encrypted json. with open(pJoin(workDir,stdString.replace('.std','.json')),'r') as encFile: decJSON = encFile.read() encData = encryptData(decJSON, key) with open(pJoin(workDir,"encryptedFiles","Encrypted_"+stdString.replace('.std','.json')),'w') as encFile: encFile.write(encData) print "Encrypted JSON file:", stdString.replace('.std','.json') # Clean up unencrypted .glm and .json. if cleanUp: try: os.remove(pJoin(workDir,stdString.replace('.std','.glm'))) print "Removed unencrypted file:", stdString.replace('.std','.glm') except: pass try: os.remove(pJoin(workDir,stdString.replace('.std','.json'))) print "Removed unencrypted file:", stdString.replace('.std','.json') except: pass print "\nDone with encrypting all test files." except: print "Failed to encrypt", stdString, seqString exceptionCount += 1 traceback.print_exc() return exceptionCount
'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 try:
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
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
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
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
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
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
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