Exemple #1
0
def calibrate_omd(start_date, omd_path, csv_path):
    """
	Modify an .omd file so that it will run in GridLAB-D with the CSV of USCRN weather data.

	:param start_date: the starting date of the GridLAB-D simulation
	:type start_date: datetime
	:param omd_path: an absolute path to the .omd file to modify
	:type omd_path: str
	:param csv_path: an absolute path to the CSV file that contains USCRN weather data
	:type csv_path: str
	"""
    with open(omd_path, 'r') as f:
        omd = json.load(f)
    tree = omd["tree"]
    # Delete all climate objects from the feeder. Also delete any csv_reader objects that are also named "WeatherReader"
    weather_reader_name = "WeatherReader"
    for key in tree.keys():
        object_type = tree[key].get("object")
        object_name = tree[key].get("name")
        if object_type == "climate" or (object_type == "csv_reader" and
                                        object_name == weather_reader_name):
            del tree[key]
    # Reinsert a new climate object and an associated csv_reader object
    oldMax = feeder.getMaxKey(tree)
    tree[oldMax + 1] = {'omftype': 'module', 'argument': 'tape'}
    tree[oldMax + 2] = {'omftype': 'module', 'argument': 'climate'}
    csv_name = os.path.basename(csv_path)
    tree[oldMax + 3] = {
        'object': 'csv_reader',
        'name': weather_reader_name,
        'filename': csv_name
    }
    climate_name = "MyClimate"
    tree[oldMax + 4] = {
        'object': 'climate',
        'name': climate_name,
        'reader': weather_reader_name,
        'tmyfile': csv_name
    }
    # Set the time correctly. Modify certain objects in the feeder (e.g. recorder and clock)
    feeder.adjustTime(
        tree, 240, 'hours',
        '{}-{}-{}'.format(start_date.year, start_date.month, start_date.day))
    omd["tree"] = tree
    # Add the weather attachment
    with open(csv_path, 'r') as f:
        weatherString = f.read()
    if omd.get("attachments") is None:
        omd["attachments"] = {}
    omd['attachments'][csv_name] = weatherString
    with open(omd_path, 'w') as f:
        json.dump(omd, f, indent=4)
Exemple #2
0
def runForeground(modelDir, inData):
    '''This reads a glm file, changes the method of powerflow and reruns'''
    print "STARTING TO RUN", modelDir
    try:
        startTime = dt.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", "IVVC1")),
        }
        #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 = dt.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 = dt.strptime(scadaDates[0].split(' PST')[0],
                                         "%Y-%m-%d %H:%M:%S")
            scadaEndDate = dt.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 = dt.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
Exemple #3
0
def attachVolts(workDir, feederPath, voltVectorA, voltVectorB, voltVectorC, simStartDate, simLength, simLengthUnits):
	'''read voltage vectors of 3 different phases, run gridlabd, and attach output to the feeder.'''
	try:
		timeStamp = [simStartDate['Date']]
		for x in range (1, 8760):
			timeStamp.append(timeStamp[x-1] + dt.timedelta(hours=1))
		firstDateTime = timeStamp[1]
		with open(pJoin(pJoin(workDir,"gridlabD"),"phaseAVoltage.player"),"w") as voltFile:
			for x in range(0, 8760):
				timestamp = timeStamp[x]
				voltage = str("%0.2f"%float(voltVectorA[x]))+"+0j"
				line = timestamp.strftime("%Y-%m-%d %H:%M:%S") + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
				voltFile.write(line)
		with open(pJoin(pJoin(workDir,"gridlabD"),"phaseBVoltage.player"),"w") as voltFile:
			for x in range(0, 8760):
				timestamp = timeStamp[x]
				voltage = str("%0.2f"%float(voltVectorB[x]))+"-"+str("%0.4f"%float(random.uniform(6449,6460)))+"j"
				line = timestamp.strftime("%Y-%m-%d %H:%M:%S") + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
				voltFile.write(line)
		with open(pJoin(pJoin(workDir,"gridlabD"),"phaseCVoltage.player"),"w") as voltFile:
			for x in range(0, 8760):
				timestamp = timeStamp[x]
				voltage = str("%0.2f"%float(voltVectorC[x]))+"+"+str("%0.4f"%float(random.uniform(6449,6460)))+"j"
				line = timestamp.strftime("%Y-%m-%d %H:%M:%S") + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
				voltFile.write(line)
		with open(feederPath, "r") as jsonIn:
			feederJson = json.load(jsonIn)
			tree = feederJson.get("tree", {})
		# Find swingNode name.
		for key in tree:
			if tree[key].get('bustype','').lower() == 'swing':
				swingName = tree[key].get('name')
		# Attach player.
		classOb = {'omftype':'class player','argument':'{double value;}'}
		voltageObA = {"object":"player", "property":"voltage_A", "file":"phaseAVoltage.player", "loop":"0", "parent":swingName}
		voltageObB = {"object":"player", "property":"voltage_B", "file":"phaseBVoltage.player", "loop":"0", "parent":swingName}
		voltageObC = {"object":"player", "property":"voltage_C", "file":"phaseCVoltage.player", "loop":"0", "parent":swingName}
		maxKey = feeder.getMaxKey(tree)
		voltplayerKeyA = maxKey + 2
		voltplayerKeyB = maxKey + 3
		voltplayerKeyC = maxKey + 4
		tree[maxKey+1] = classOb
		tree[voltplayerKeyA] = voltageObA
		tree[voltplayerKeyB] = voltageObB
		tree[voltplayerKeyC] = voltageObC
		# Adjust time and run output.
		feeder.adjustTime(tree, simLength, simLengthUnits, firstDateTime.strftime("%Y-%m-%d %H:%M:%S"))
		output = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=pJoin(workDir,"gridlabD"))
		# Write the output.
		with open(pJoin(workDir,"calibratedFeeder.omd"),"w") as outJson:
			playerStringA = open(pJoin(pJoin(workDir,"gridlabD"),"phaseAVoltage.player")).read()
			playerStringB = open(pJoin(pJoin(workDir,"gridlabD"),"phaseBVoltage.player")).read()
			playerStringC = open(pJoin(pJoin(workDir,"gridlabD"),"phaseCVoltage.player")).read()
			feederJson["attachments"]["phaseAVoltage.player"] = playerStringA
			feederJson["attachments"]["phaseBVoltage.player"] = playerStringB
			feederJson["attachments"]["phaseCVoltage.player"] = playerStringC
			feederJson["tree"] = tree
			json.dump(feederJson, outJson, indent=4)
		return pJoin(workDir,"calibratedFeeder.omd"), True
	except:
		print "Failed to run gridlabD with voltage players."
		return "", False
Exemple #4
0
def omfCalibrate(workDir, feederPath, scadaPath, simStartDate, simLength, simLengthUnits, solver="FBS", calibrateError=(0.05,5), trim=5):
	'''calibrates a feeder and saves the calibrated tree at a location.
	Note: feeders with cap banks should be calibrated with cap banks OPEN.
	We have seen cap banks throw off calibration.'''
	with open(feederPath, "r") as jsonIn:
		feederJson = json.load(jsonIn)
		tree = feederJson.get("tree", {})
	simLength = simLength + trim
	# Process scada data.
	scadaSubPower = _processScadaData(pJoin(workDir,"gridlabD"),scadaPath, simStartDate, simLengthUnits)
	# Load specified solver.
	for key in tree:
		if tree[key].get("module","").lower() == "powerflow":
			tree[key] = {"module":"powerflow","solver_method":solver}	
	# Attach player.
	classOb = {'omftype':'class player','argument':'{double value;}'}
	playerOb = {"object":"player", "property":"value", "name":"scadaLoads", "file":"subScada.player", "loop":"0"}
	maxKey = feeder.getMaxKey(tree)
	playerKey = maxKey + 2
	tree[maxKey+1] = classOb
	tree[playerKey] = playerOb
	# Make loads reference player.
	loadTemplate = {"object": "triplex_load",
		"power_pf_12": "0.95",
		"impedance_pf_12": "0.98",
		"power_pf_12": "0.90",
		"impedance_fraction_12": "0.7",
		"power_fraction_12": "0.3"}
	loadTemplateR = {"object": "load",
		"impedance_pf_A": "0.98",
		"impedance_pf_B": "0.98",
		"impedance_pf_C": "0.98",
		"power_pf_A": "0.90",
		"power_pf_B": "0.90",
		"power_pf_C": "0.90",
		"impedance_fraction_A": "0.7",
		"impedance_fraction_B": "0.7",
		"impedance_fraction_C": "0.7",
		"power_fraction_A": "0.3",
		"power_fraction_B": "0.3",
		"power_fraction_C": "0.3"}		
	for key in tree:
		ob = tree[key]
		if ob.get("object","") in ("triplex_node", "triplex_load") and (ob.get("power_12") or ob.get("base_power_12")):
			# Add to triplex_nodes.
			newOb = dict(loadTemplate)
			newOb["name"] = ob.get("name", "")
			newOb["parent"] = ob.get("parent", "")
			newOb["phases"] = ob.get("phases", "")
			newOb["nominal_voltage"] = ob.get("nominal_voltage","")
			newOb["latitude"] = ob.get("latitude","0")
			newOb["longitude"] = ob.get("longitude","0")
			oldPow = ob.get("power_12","").replace("j","d")
			if not oldPow:
				oldPow = ob.get("base_power_12")
				if "scadaloads.value*" in oldPow:
					oldPow = oldPow[17:]
			pythagPower = gridlabd._strClean(oldPow)
			newOb["base_power_12"] = "scadaLoads.value*" + str(pythagPower)
			tree[key] = newOb
		elif ob.get("object","") == "load":
			# Add to residential_loads too.
			newOb = dict(loadTemplateR)
			newOb["name"] = ob.get("name", "")
			newOb["parent"] = ob.get("parent", "")
			newOb["phases"] = ob.get("phases", "")
			newOb["load_class"] = ob.get("load_class", "")
			newOb["nominal_voltage"] = ob.get("nominal_voltage","")
			newOb["latitude"] = ob.get("latitude","0")
			newOb["longitude"] = ob.get("longitude","0")
			try:
				oldPow = ob.get("constant_power_A","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_A"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			try:
				oldPow = ob.get("constant_power_B","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_B"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			try:
				oldPow = ob.get("constant_power_C","").replace("j","d")
				pythagPower = gridlabd._strClean(oldPow)
				newOb["base_power_C"] = "scadaLoads.value*" + str(pythagPower)
			except:
				pass
			tree[key] = newOb
	# Convert swing bus to a meter.
	for key in tree:
		if tree[key].get('bustype','').lower() == 'swing' and tree[key].get('object','') != 'meter':
			swingName = tree[key].get('name')
			regIndex = key
			tree[key]['object'] = 'meter'	
	# Search for the substation meter and attach a recorder there.
	for key in tree:
		if tree[key].get('bustype','').lower() == 'swing':
			swingName = tree[key].get('name')
	recOb = {"object": "recorder",
		"parent": swingName,
		"property": "measured_real_power,measured_reactive_power,measured_power",
		"file": "caliSub.csv",
		"interval": "3600"}
	outputRecorderKey = maxKey + 3
	tree[outputRecorderKey] = recOb
	feeder.adjustTime(tree, simLength, simLengthUnits, simStartDate['Date'].strftime("%Y-%m-%d %H:%M:%S"))
	# Run Gridlabd, calculate scaling constant.
	def runPowerflowIter(tree,scadaSubPower):
		'''Runs powerflow once, then iterates.'''
		# Run initial powerflow to get power.
		print "Starting calibration."
		print "Goal of calibration: Error: %s, Iterations: <%s, trim: %s"%(calibrateError[0], calibrateError[1], trim)		
		output = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=pJoin(workDir,"gridlabD"))
		outRealPow = output["caliSub.csv"]["measured_real_power"][trim:simLength]
		outImagPower = output["caliSub.csv"]["measured_reactive_power"][trim:simLength]
		outAppPowerKw = [(x[0]**2 + x[1]**2)**0.5/1000 for x in zip(outRealPow, outImagPower)]
		lastFile = "subScada.player"
		nextFile = "subScadaCalibrated.player"
		nextPower = outAppPowerKw
		error = (sum(outRealPow)/1000-sum(scadaSubPower))/sum(scadaSubPower)
		iteration = 1
		print "First error:", error
		while abs(error)>calibrateError[0] and iteration<calibrateError[1]:
			# Run calibration and iterate up to 5 times.
			SCAL_CONST = sum(scadaSubPower)/sum(nextPower)
			print "Calibrating & running again... Error: %s, Iteration: %s, SCAL_CONST: %s"%(str(round(abs(error*100),6)), str(iteration), round(SCAL_CONST,6))
			newPlayData = []
			with open(pJoin(pJoin(workDir,"gridlabD"), lastFile), "r") as playerFile:
				for line in playerFile:
					(key,val) = line.split(',')
					newPlayData.append(str(key) + ',' + str(float(val)*SCAL_CONST) + "\n")
			with open(pJoin(pJoin(workDir,"gridlabD"), nextFile), "w") as playerFile:
				for row in newPlayData:
					playerFile.write(row)
			tree[playerKey]["file"] = nextFile
			tree[outputRecorderKey]["file"] = "caliSubCheck.csv"
			nextOutput = gridlabd.runInFilesystem(tree, keepFiles=True, workDir=pJoin(workDir,"gridlabD"))
			outRealPowIter = nextOutput["caliSubCheck.csv"]["measured_real_power"][trim:simLength]
			outImagPowerIter = nextOutput["caliSubCheck.csv"]["measured_reactive_power"][trim:simLength]
			nextAppKw = [(x[0]**2 + x[1]**2)**0.5/1000
				for x in zip(outRealPowIter, outImagPowerIter)]
			lastFile = nextFile
			nextFile = "subScadaCalibrated"+str(iteration)+".player"
			nextPower = nextAppKw
			# Compute error and iterate.
			error = (sum(outRealPowIter)/1000-sum(scadaSubPower))/sum(scadaSubPower)
			iteration+=1
		else:
			if iteration==1: outRealPowIter = outRealPow
			SCAL_CONST = 1.0
		print "Calibration done: Error: %s, Iteration: %s, SCAL_CONST: %s"%(str(round(abs(error*100),2)), str(iteration), round(SCAL_CONST,2))		
		return outRealPow, outRealPowIter, lastFile, iteration
	outRealPow, outRealPowIter, lastFile, iteration = runPowerflowIter(tree,scadaSubPower[trim:simLength])
	caliPowVectors = [[float(element) for element in scadaSubPower[trim:simLength]], [float(element)/1000 for element in outRealPow], [float(element)/1000 for element in outRealPowIter]]
	labels = ["scadaSubPower","initialGuess","finalGuess"]
	colors = ['red','lightblue','blue']
	chartData = {"Title":"Substation Calibration Check (Iterated "+str(iteration+1)+"X)", "fileName":"caliCheckPlot", "colors":colors,"labels":labels, "timeZone":simStartDate['timeZone']}
	# Trimming vectors to make them all the same length as the smallest vector
	minCaliPowVecLen = min(len(caliPowVectors[0]), len(caliPowVectors[1]), len(caliPowVectors[2]))
	caliPowVectors[0] = caliPowVectors[0][:minCaliPowVecLen]
	caliPowVectors[1] = caliPowVectors[1][:minCaliPowVecLen]
	caliPowVectors[2] = caliPowVectors[2][:minCaliPowVecLen]
	print "Len:", len(caliPowVectors[0]), len(caliPowVectors[1]), len(caliPowVectors[2])
	plotLine(workDir, caliPowVectors, chartData, simStartDate['Date']+dt.timedelta(hours=trim), simLengthUnits)
	# Write the final output.
	with open(pJoin(workDir,"calibratedFeeder.omd"),"w") as outJson:
		playerString = open(pJoin(pJoin(workDir,"gridlabD"),lastFile)).read()
		feederJson["attachments"][lastFile] = playerString
		feederJson["tree"] = tree
		json.dump(feederJson, outJson, indent=4)
	return
Exemple #5
0
def heavyProcessing(modelDir, inputDict):
	''' Run the model in its directory. WARNING: GRIDLAB CAN TAKE HOURS TO COMPLETE. '''
	print "STARTING TO RUN", modelDir
	beginTime = datetime.datetime.now()
	# Get feeder name and data in.
	try: os.mkdir(pJoin(modelDir,'gldContainer'))
	except: pass
	try:	
		feederName = inputDict["feederName1"]
		weather = inputDict["weather"]
		if weather == "typical":
			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()
		else:
			#hack for testing
			makeClimateCsv('2010-07-01', '2010-08-01', 'DFW', 'Output/Automated dsoSimSuite Test/gldContainer/weather.csv')
			startTime = datetime.datetime.now()
		startTime = datetime.datetime.now()
		feederJson = json.load(open(pJoin(modelDir, feederName+'.omd')))
		tree = feederJson["tree"]
		#add a check to see if there is already a climate object in the omd file
		#if there is delete the climate from attachments and the climate object
		attachKeys = feederJson["attachments"].keys()
		for key in attachKeys:
			if key.endswith('.tmy2'):
				del feederJson['attachments'][key]	
		treeKeys = feederJson["tree"].keys()
		for key in treeKeys:
			if 'object' in feederJson['tree'][key]:
			 	if feederJson['tree'][key]['object'] == 'climate':
			 		del feederJson['tree'][key]	
		#add weather objects and modules to .glm if there is no climate file in the omd file
		if weather == "historical":
			oldMax = feeder.getMaxKey(tree)
			tree[oldMax + 1] = {'omftype':'module', 'argument':'tape'}
			tree[oldMax + 2] = {'omftype':'module', 'argument':'climate'}
			tree[oldMax + 3] = {'object':'csv_reader', 'name':'weatherReader', 'filename':'weather.csv'}
			tree[oldMax + 4] = {'object':'climate', 'name':'exampleClimate', 'tmyfile':'weather.csv', 'reader':'weatherReader'}
		else:
			oldMax = feeder.getMaxKey(tree)
			tree[oldMax + 1] ={'object':'climate','name':'Climate','interpolate':'QUADRATIC', 'tmyfile':'climate.tmy2'}
		# 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
Exemple #6
0
def attachVolts(workDir, feederPath, voltVectorA, voltVectorB, voltVectorC,
                simStartDate, simLength, simLengthUnits):
    '''read voltage vectors of 3 different phases, run gridlabd, and attach output to the feeder.'''
    try:
        timeStamp = [simStartDate['Date']]
        for x in range(1, 8760):
            timeStamp.append(timeStamp[x - 1] + dt.timedelta(hours=1))
        firstDateTime = timeStamp[1]
        with open(pJoin(pJoin(workDir, "gridlabD"), "phaseAVoltage.player"),
                  "w") as voltFile:
            for x in range(0, 8760):
                timestamp = timeStamp[x]
                voltage = str("%0.2f" % float(voltVectorA[x])) + "+0j"
                line = timestamp.strftime(
                    "%Y-%m-%d %H:%M:%S"
                ) + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
                voltFile.write(line)
        with open(pJoin(pJoin(workDir, "gridlabD"), "phaseBVoltage.player"),
                  "w") as voltFile:
            for x in range(0, 8760):
                timestamp = timeStamp[x]
                voltage = str("%0.2f" % float(voltVectorB[x])) + "-" + str(
                    "%0.4f" % float(random.uniform(6449, 6460))) + "j"
                line = timestamp.strftime(
                    "%Y-%m-%d %H:%M:%S"
                ) + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
                voltFile.write(line)
        with open(pJoin(pJoin(workDir, "gridlabD"), "phaseCVoltage.player"),
                  "w") as voltFile:
            for x in range(0, 8760):
                timestamp = timeStamp[x]
                voltage = str("%0.2f" % float(voltVectorC[x])) + "+" + str(
                    "%0.4f" % float(random.uniform(6449, 6460))) + "j"
                line = timestamp.strftime(
                    "%Y-%m-%d %H:%M:%S"
                ) + " " + simStartDate['timeZone'] + "," + str(voltage) + "\n"
                voltFile.write(line)
        with open(feederPath, "r") as jsonIn:
            feederJson = json.load(jsonIn)
            tree = feederJson.get("tree", {})
        # Find swingNode name.
        for key in tree:
            if tree[key].get('bustype', '').lower() == 'swing':
                swingName = tree[key].get('name')
        # Attach player.
        classOb = {'omftype': 'class player', 'argument': '{double value;}'}
        voltageObA = {
            "object": "player",
            "property": "voltage_A",
            "file": "phaseAVoltage.player",
            "loop": "0",
            "parent": swingName
        }
        voltageObB = {
            "object": "player",
            "property": "voltage_B",
            "file": "phaseBVoltage.player",
            "loop": "0",
            "parent": swingName
        }
        voltageObC = {
            "object": "player",
            "property": "voltage_C",
            "file": "phaseCVoltage.player",
            "loop": "0",
            "parent": swingName
        }
        maxKey = feeder.getMaxKey(tree)
        voltplayerKeyA = maxKey + 2
        voltplayerKeyB = maxKey + 3
        voltplayerKeyC = maxKey + 4
        tree[maxKey + 1] = classOb
        tree[voltplayerKeyA] = voltageObA
        tree[voltplayerKeyB] = voltageObB
        tree[voltplayerKeyC] = voltageObC
        # Adjust time and run output.
        feeder.adjustTime(tree, simLength, simLengthUnits,
                          firstDateTime.strftime("%Y-%m-%d %H:%M:%S"))
        output = gridlabd.runInFilesystem(tree,
                                          keepFiles=True,
                                          workDir=pJoin(workDir, "gridlabD"))
        # Write the output.
        with open(pJoin(workDir, "calibratedFeeder.omd"), "w") as outJson:
            playerStringA = open(
                pJoin(pJoin(workDir, "gridlabD"),
                      "phaseAVoltage.player")).read()
            playerStringB = open(
                pJoin(pJoin(workDir, "gridlabD"),
                      "phaseBVoltage.player")).read()
            playerStringC = open(
                pJoin(pJoin(workDir, "gridlabD"),
                      "phaseCVoltage.player")).read()
            feederJson["attachments"]["phaseAVoltage.player"] = playerStringA
            feederJson["attachments"]["phaseBVoltage.player"] = playerStringB
            feederJson["attachments"]["phaseCVoltage.player"] = playerStringC
            feederJson["tree"] = tree
            json.dump(feederJson, outJson, indent=4)
        return pJoin(workDir, "calibratedFeeder.omd"), True
    except:
        print "Failed to run gridlabD with voltage players."
        return "", False
Exemple #7
0
# Delete all climate then reinsert.
reader_name = 'weatherReader'
climate_name = 'MyClimate'
for key in myTree.keys():
	obName = myTree[key].get('name','')
	obType = myTree[key].get('object','')
	if obName in [reader_name, climate_name] or obType is 'climate':
		del myTree[key]
oldMax = feeder.getMaxKey(myTree)
myTree[oldMax + 1] = {'omftype':'module', 'argument':'tape'}
myTree[oldMax + 2] = {'omftype':'module', 'argument':'climate'}
myTree[oldMax + 3] = {'object':'csv_reader', 'name':reader_name, 'filename':CSV_NAME}
myTree[oldMax + 4] = {'object':'climate', 'name':climate_name, 'reader': reader_name, 'tmyfile':CSV_NAME}

# Set the time correctly.
feeder.adjustTime(myTree, 240, 'hours', '{}-{}-{}'.format(INIT_TIME.year, INIT_TIME.month, INIT_TIME.day))

# Run here to test.
rawOut = runInFilesystem(myTree, attachments=[], keepFiles=True, workDir='.', glmName='./outFile.glm')

# Write back the full feeder.
# outJson = dict(myFeed)
# with open(CSV_NAME,'r') as weatherFile:
# 	weatherString = weatherFile.read()
# outJson['attachments']['weatheryearDCA.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:
# 	json.dump(outJson, outFile, indent=4)
Exemple #8
0
def heavyProcessing(modelDir, inputDict):
	''' Run the model in its directory. WARNING: GRIDLAB CAN TAKE HOURS TO COMPLETE. '''
	print "STARTING TO RUN", modelDir
	beginTime = datetime.datetime.now()
	# Get feeder name and data in.
	try: os.mkdir(pJoin(modelDir,'gldContainer'))
	except: pass
	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"]
		#add a check to see if there is already a climate object in the omd file
		#if there is delete the climate from attachments and the climate object
		attachKeys = feederJson["attachments"].keys()
		for key in attachKeys:
			if key.endswith('.tmy2'):
				del feederJson['attachments'][key]	
		treeKeys = feederJson["tree"].keys()
		for key in treeKeys:
			if 'object' in feederJson['tree'][key]:
			 	if feederJson['tree'][key]['object'] == 'climate':
			 		del feederJson['tree'][key]
		oldMax = feeder.getMaxKey(tree)
		tree[oldMax + 1] = {'omftype':'module', 'argument':'climate'}
		tree[oldMax + 2] ={'object':'climate','name':'Climate','interpolate':'QUADRATIC', 'tmyfile':'climate.tmy2'}
		# 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
Exemple #9
0
def heavyProcessing(modelDir, inputDict):
	''' Run the model in its directory. WARNING: GRIDLAB CAN TAKE HOURS TO COMPLETE. '''
	print "STARTING TO RUN", modelDir
	beginTime = datetime.datetime.now()
	# Get feeder name and data in.
	try: os.mkdir(pJoin(modelDir,'gldContainer'))
	except: pass
	try:	
		feederName = inputDict["feederName1"]
		inputDict["climateName"], latforpvwatts = zipCodeToClimateName(inputDict["zipCode"])
		shutil.copy(pJoin(__metaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"),
			pJoin(modelDir, "gldContainer", "climate.tmy2"))
		startTime = datetime.datetime.now()
		feederJson = json.load(open(pJoin(modelDir, feederName+'.omd')))
		tree = feederJson["tree"]
		#add a check to see if there is already a climate object in the omd file
		#if there is delete the climate from attachments and the climate object
		attachKeys = feederJson["attachments"].keys()
		for key in attachKeys:
			if key.endswith('.tmy2'):
				del feederJson['attachments'][key]	
		treeKeys = feederJson["tree"].keys()
		for key in treeKeys:
			if 'object' in feederJson['tree'][key]:
			 	if feederJson['tree'][key]['object'] == 'climate':
			 		del feederJson['tree'][key]
		oldMax = feeder.getMaxKey(tree)
		tree[oldMax + 1] = {'omftype':'module','argument':'climate'}
		tree[oldMax + 2] = {'object':'climate','name':'Climate','interpolate':'QUADRATIC','tmyfile':'climate.tmy2'}
		# tree[oldMax + 3] = {'object':'capacitor','control':'VOLT','phases':'ABCN','name':'CAPTEST','parent':'tm_1','capacitor_A':'0.10 MVAr','capacitor_B':'0.10 MVAr','capacitor_C':'0.10 MVAr','time_delay':'300.0','nominal_voltage':'2401.7771','voltage_set_high':'2350.0','voltage_set_low':'2340.0','switchA':'CLOSED','switchB':'CLOSED','switchC':'CLOSED','control_level':'INDIVIDUAL','phases_connected':'ABCN','dwell_time':'0.0','pt_phases':'ABCN'}
		# 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 recorder for waterheaters on/off
		stub = {'object':'group_recorder', 'group':'"class=waterheater"', 'property':'is_waterheater_on', 'interval':3600, 'file':'allWaterheaterOn.csv'}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub
		# Attach recorder for waterheater tank temperatures
		stub = {'object':'group_recorder', 'group':'"class=waterheater"', 'property':'temperature', 'interval':3600, 'file':'allWaterheaterTemp.csv'}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub
		# Attach collector for total waterheater load
		stub = {'object':'collector', 'group':'"class=waterheater"', 'property':'sum(actual_load)', 'interval':3600, 'file':'allWaterheaterLoad.csv'}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub
		# Attach collector for total network load
		stub = {'object':'collector', 'group':'"class=triplex_meter"', 'property':'sum(measured_real_power)', 'interval':3600, 'file':'allMeterPower.csv'}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub

		# Attach collector for total overall ZIPload power/load
		stub = {'object':'collector', 'group':'"class=ZIPload"', 'property':'sum(base_power)', 'interval':3600, 'file':'allZIPloadPower.csv'}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub
		# Attach recorder for each ZIPload power/load
		stub = {'object':'group_recorder', 'group':'"class=ZIPload"', 'property':'base_power', 'interval':3600, 'file':'eachZIPloadPower.csv'}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub
		# Attach recorder for all ZIPloads demand_rate
		stub = {'object':'group_recorder', 'group':'"class=ZIPload"', 'property':'demand_rate', 'interval':3600, 'file':'allZIPloadDemand.csv'}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub
		# Attach recorder for all ZIPloads on
		stub = {'object':'group_recorder', 'group':'"class=ZIPload"', 'property':'number_of_devices_on', 'interval':3600, 'file':'allZIPloadOn.csv'}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub

		# Attach passive_controller	
		tree[feeder.getMaxKey(tree)+1] = {'omftype':'module','argument':'market'}
		tree[feeder.getMaxKey(tree)+1] = {'omftype':'class auction','argument':'{\n\tdouble my_avg; double my_std;\n}'}
		tree[feeder.getMaxKey(tree)+1] = {'omftype':'class player','argument':'{\n\tdouble value;\n}'}

		stub = {
			'object':'player',
			'name':'cppDays',
			'file':'superCpp.player'
		}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub

		stub = {
			'object':'player',
			'name':'superClearing',
			'file':'superClearingPrice.player',
			'loop':10
		}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub

		stub = {
			'object':'auction',
			'name':'MARKET_1',
			'my_std':0.037953,
			'period':900,
			'my_avg':0.110000,
			'current_market.clearing_price':'superClearing.value',
			'special_mode':'BUYERS_ONLY',
			'unit': 'kW'
		}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub

		stub = {
			'object':'passive_controller',
			'name':'waterheater_controller_waterheater171923',
			'parent':'waterheater171923',
			'control_mode':'RAMP',
			'range_high':5,
			'range_low':-5,
			'ramp_high':1,
			'ramp_low':-1,
			'period':900,
			'setpoint':'is_waterheater_on',
			'base_setpoint':1,
			'expectation_object':'MARKET_1',
			'expectation_property':'my_avg',
			'observation_object':'MARKET_1',
			'observation_property':'past_market.clearing_price',
			'stdev_observation_property':'my_std',
			'state_property':'override'
		}
		copyStub = dict(stub)
		tree[feeder.getMaxKey(tree)+1] = copyStub

		# stub = {
		# 	'object':'passive_controller',
		# 	'name':'ZIPload_controller_ZIPload171922',
		# 	'parent':'ZIPload171922',
		# 	'control_mode':'RAMP',
		# 	'range_high':5,
		# 	'range_low':-5,
		# 	'ramp_high':1,
		# 	'ramp_low':-1,
		# 	'period':900,
		# 	'setpoint':'base_power'
		# 	'base_setpoint':1,
		# 	'expectation_object':'MARKET_1',
		# 	'expectation_property':'my_avg',
		# 	'observation_object':'MARKET_1',
		# 	'observation_property':'past_market.clearing_price',
		# 	'stdev_observation_property':'my_std'
		# 	'state_property':'override'
		# }
		# copyStub = dict(stub)
		# tree[feeder.getMaxKey(tree)+1] = copyStub

		# Attach recorders for system voltage map:
		stub = {'object':'group_recorder', 'group':'"class=node"', 'interval':3600}
		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
		# Attach recorders for system voltage map, triplex:
		stub = {'object':'group_recorder', 'group':'"class=triplex_node"', 'interval':3600}
		for phase in ['1','2']:
			copyStub = dict(stub)
			copyStub['property'] = 'voltage_' + phase
			copyStub['file'] = phase.lower() + 'nVoltDump.csv'
			tree[feeder.getMaxKey(tree) + 1] = copyStub
		# And get meters for system voltage map:
		stub = {'object':'group_recorder', 'group':'"class=triplex_meter"', 'interval':3600}
		for phase in ['1','2']:
			copyStub = dict(stub)
			copyStub['property'] = 'voltage_' + phase
			copyStub['file'] = phase.lower() + 'mVoltDump.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:
			print key
			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]

		# Print gridBallast Outputs to allOutputData.json
		cleanOut['gridBallast'] = {}
		if 'allWaterheaterOn.csv' in rawOut:
			cleanOut['gridBallast']['waterheaterOn'] = {}
			for key in rawOut['allWaterheaterOn.csv']:
				if key.startswith('waterheater'):
					cleanOut['gridBallast']['waterheaterOn'][key] = rawOut.get('allWaterheaterOn.csv')[key]
		if 'allWaterheaterTemp.csv' in rawOut:
			cleanOut['gridBallast']['waterheaterTemp'] = {}
			for key in rawOut['allWaterheaterTemp.csv']:
				if key.startswith('waterheater'):
					cleanOut['gridBallast']['waterheaterTemp'][key] = rawOut.get('allWaterheaterTemp.csv')[key]
		if 'allMeterPower.csv' in rawOut:
			cleanOut['gridBallast']['totalNetworkLoad'] = rawOut.get('allMeterPower.csv')['sum(measured_real_power)']

		if ('allWaterheaterLoad.csv' in rawOut) and ('allZIPloadPower.csv' in rawOut):
			cleanOut['gridBallast']['availabilityMagnitude'] = [x + y for x, y in zip(rawOut.get('allWaterheaterLoad.csv')['sum(actual_load)'], rawOut.get('allZIPloadPower.csv')['sum(base_power)'])]
		if 'eachZIPloadPower.csv' in rawOut:
			cleanOut['gridBallast']['ZIPloadPower'] = {}
			for key in rawOut['eachZIPloadPower.csv']:
				if key.startswith('ZIPload'):
					cleanOut['gridBallast']['ZIPloadPower'][key] = rawOut.get('eachZIPloadPower.csv')[key]
		if 'allZIPloadDemand.csv' in rawOut:
			cleanOut['gridBallast']['ZIPloadDemand'] = {}
			for key in rawOut['allZIPloadDemand.csv']:
				if key.startswith('ZIPload'):
					cleanOut['gridBallast']['ZIPloadDemand'][key] = rawOut.get('allZIPloadDemand.csv')[key]
		if 'allZIPloadOn.csv' in rawOut:
			cleanOut['gridBallast']['ZIPloadOn'] = {}
			for key in rawOut['allZIPloadOn.csv']:
				if key.startswith('ZIPload'):
					cleanOut['gridBallast']['ZIPloadOn'][key] = rawOut.get('allZIPloadOn.csv')[key]

		# EventTime calculations
		eventTime = inputDict['eventTime']
		eventLength = inputDict['eventLength']
		eventLength = eventLength.split(':')
		eventDuration = datetime.timedelta(hours=int(eventLength[0]), minutes=int(eventLength[1]))
		eventStart = datetime.datetime.strptime(eventTime, '%Y-%m-%d %H:%M')
		eventEnd = eventStart + eventDuration
		cleanOut['gridBallast']['eventStart'] = str(eventStart)
		cleanOut['gridBallast']['eventEnd'] = str(eventEnd)
		# Drop timezone from timeStamp, Convert string to date
		timeStamps = [x[:19] for x in cleanOut['timeStamps']]
		dateTimeStamps = [datetime.datetime.strptime(x, '%Y-%m-%d %H:%M:%S') for x in timeStamps]	
		eventEndIdx =  dateTimeStamps.index(eventEnd)
		# Recovery Time
		whOn = cleanOut['gridBallast']['waterheaterOn']
		whOnList = whOn.values()
		whOnZip = zip(*whOnList)
		whOnSum = [sum(x) for x in whOnZip]
		anyOn = [x > 0 for x in whOnSum] 
		tRecIdx = anyOn.index(True, eventEndIdx)
		tRec = dateTimeStamps[tRecIdx]
		cleanOut['gridBallast']['recoveryTime'] = str(tRec)
		# Waterheaters Off-Duration
		offDuration = tRec - eventStart
		cleanOut['gridBallast']['offDuration'] = str(offDuration)
		# Reserve Magnitude Target (RMT)
		availMag = cleanOut['gridBallast']['availabilityMagnitude']
		totNetLoad = cleanOut['gridBallast']['totalNetworkLoad']
		# loadZip = zip(availMag,totNetLoad)
		# rmt = [x[0]/x[1] for x in loadZip]
		rmt = (1000*sum(availMag))/sum(totNetLoad)
		cleanOut['gridBallast']['rmt'] = rmt
		# Reserve Magnitude Variability Tolerance (RMVT)
		avgAvailMag = sum(availMag)/len(availMag)
		rmvtMax = max(availMag)/avgAvailMag
		rmvtMin = min(availMag)/avgAvailMag
		rmvt = rmvtMax - rmvtMin
		cleanOut['gridBallast']['rmvt'] = rmvt
		# Availability
		notAvail = availMag.count(0)/len(timeStamps)
		avail = (1-notAvail)*100
		cleanOut['gridBallast']['availability'] = avail
		# Waterheater Temperature Drop calculations
		whTemp = cleanOut['gridBallast']['waterheaterTemp']
		whTempList = whTemp.values()
		whTempZip = zip(*whTempList)
		whTempDrops = []
		LOWER_LIMIT_TEMP = 125 # Used for calculating quality of service.
		for time in whTempZip:
			tempDrop = sum([t < LOWER_LIMIT_TEMP for t in time])
			whTempDrops.append(tempDrop)
		cleanOut['gridBallast']['waterheaterTempDrops'] = whTempDrops

		# ZIPload calculations for Availability and QoS
		zPower = cleanOut['gridBallast']['ZIPloadPower']
		zPowerList = zPower.values()
		zPowerZip = zip(*zPowerList)
		zPowerSum = [sum(x) for x in zPowerZip]
		zDemand = cleanOut['gridBallast']['ZIPloadDemand']
		zDemandList  = zDemand.values()
		zDemandZip = zip(*zDemandList)
		zDrops = []
		for time in zDemandZip:
			for each in zPowerZip:
				zIdx = 0
				if each[zIdx] == 0:
					zPowerIdx += 1
					zDrop = sum([t > 0 for t in time])
					zDrops.append(zDrop)
				else:
					zDrops.append(0)
		cleanOut['gridBallast']['qualityDrops'] = [x + y for x, y in zip(whTempDrops, zDrops)]

		# 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
def work(modelDir, inputDict):
	feederName = inputDict["feederName1"]
	inputDict["climateName"] = zipCodeToClimateName(inputDict["zipCode"])
	shutil.copy(pJoin(__neoMetaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"),
		pJoin(modelDir, "climate.tmy2"))
	feederJson = json.load(open(pJoin(modelDir, feederName+'.omd')))
	tree = feederJson["tree"]
	# tree[feeder.getMaxKey(tree)+1] = {'object':'capacitor','control':'VOLT','phases':'ABCN','name':'CAPTEST','parent':'tm_1','capacitor_A':'0.10 MVAr','capacitor_B':'0.10 MVAr','capacitor_C':'0.10 MVAr','time_delay':'300.0','nominal_voltage':'2401.7771','voltage_set_high':'2350.0','voltage_set_low':'2340.0','switchA':'CLOSED','switchB':'CLOSED','switchC':'CLOSED','control_level':'INDIVIDUAL','phases_connected':'ABCN','dwell_time':'0.0','pt_phases':'ABCN'}
	# 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)

	# System check - linux doesn't support newer GridLAB-D versions
	if sys.platform == 'linux2':
		pass
	else:
		# print feeder.getMaxKey(tree)
		# tree[14,20,27,28,47] empty for UCS Egan, add climate object to tree[14]
		# HACK: tree[10:19] is empty
		tree[11] = {'omftype':'#include', 'argument':'\"hot_water_demand.glm\"'}
		tree[12] = {'omftype':'#include', 'argument':'\"lock_mode_schedule.glm\"'}
		tree[13] = {'omftype':'#include', 'argument':'\"control_priority_schedule.glm\"'}
		# Attach frequency player
		tree[14] = {'omftype':'class player', 'argument':'{double value;}'}
		tree[feeder.getMaxKey(tree)+1] = {'object':'player', 'file':'frequency.PLAYER', 'property':'value', 'name':'frequency', 'loop':0}
		# Set up GridBallast Controls
		totalWH = 0
		totalZIP = 0
		gbWH = 0
		gbZIP = 0
		for key in tree.keys():
			# Waterheater Controller properties
			if ('name' in tree[key]) and (tree[key].get('object') == 'waterheater'):
		 		totalWH += 1
	 			gbWH += 1
	 			# Frequency control parameters
	 			tree[key]['enable_freq_control'] = 'true'
	 			tree[key]['measured_frequency'] = 'frequency.value'
	 			tree[key]['freq_lowlimit'] = 59
	 			tree[key]['freq_uplimit'] = 61
	 			tree[key]['heat_mode'] = 'ELECTRIC'
	 			# tree[key]['average_delay_time'] = 60
	 			# Voltage control parameters
	 			# tree[key]['enable_volt_control'] = 'true'
	 			# tree[key]['volt_lowlimit'] = 240.4
	 			# tree[key]['volt_uplimit'] = 241.4
	 			# Lock Mode parameters
	 			# tree[key]['enable_lock'] = 'temp_lock_enable'
	 			# tree[key]['lock_STATUS'] = 'temp_lock_status'
	 			# Controller Priority: a.lock, b.freq, c.volt, d.therm
	 			tree[key]['controller_priority'] = 3214 #default:therm>lock>freq>volt
	 			# tree[key]['controller_priority'] = 1423 #freq>therm>volt>lock
	 			# tree[key]['controller_priority'] = 'control_priority'
		 		# fix waterheater property demand to water_demand for newer GridLAB-D versions
		 		if 'demand' in tree[key]:
		 			# tree[key]['water_demand'] = tree[key]['demand']
		 			tree[key]['water_demand'] = 'weekday_hotwater*1'
		 			del tree[key]['demand']
			# ZIPload Controller properties
			if ('name' in tree[key]) and (tree[key].get('object') == 'ZIPload'):
		 		totalZIP += 1
				if tree[key]['name'].startswith('responsive'):
		 			gbZIP += 1
			 		# Frequency control parameters
		 			tree[key]['enable_freq_control'] = 'true'
		 			tree[key]['measured_frequency'] = 'frequency.value'
		 			tree[key]['freq_lowlimit'] = 59
		 			tree[key]['freq_uplimit'] = 61
		 			# tree[key]['average_delay_time'] = 60
		 			# Voltage control parameters
		 			# tree[key]['enable_volt_control'] = 'true'
		 			# tree[key]['volt_lowlimit'] = 240.4
		 			# tree[key]['volt_uplimit'] = 241.4
		 			# Lock Mode parameters
		 			# tree[key]['enable_lock'] = 'temp_lock_enable'
		 			# tree[key]['lock_STATUS'] = 'temp_lock_status'
		 			tree[key]['controller_priority'] = 4321 #default:lock>freq>volt>therm
		 			# tree[key]['controller_priority'] = 2431 #freq>volt>lock>therm
		 			# tree[key]['groupid'] = 'fan'

	# Attach collector for total network load
	tree[feeder.getMaxKey(tree)+1] = {'object':'collector', 'group':'"class=triplex_meter"', 'property':'sum(measured_real_power)', 'interval':60, 'file':'allMeterPower.csv'}
	# Attach collector for total waterheater load
	tree[feeder.getMaxKey(tree)+1] = {'object':'collector', 'group':'"class=waterheater"', 'property':'sum(actual_load)', 'interval':60, 'file':'allWaterheaterLoad.csv'}
	# Attach collector for total ZIPload power/load
	tree[feeder.getMaxKey(tree)+1] = {'object':'collector', 'group':'"class=ZIPload"', 'property':'sum(base_power)', 'interval':60, 'file':'allZIPloadPower.csv'}
	# Attach recorder for each ZIPload power/load
	tree[feeder.getMaxKey(tree)+1] = {'object':'group_recorder', 'group':'"class=ZIPload"', 'property':'base_power', 'interval':60, 'file':'eachZIPloadPower.csv'}
	# Attach recorder for all ZIPloads demand_rate
	tree[feeder.getMaxKey(tree)+1] = {'object':'group_recorder', 'group':'"class=ZIPload"', 'property':'demand_rate', 'interval':60, 'file':'allZIPloadDemand.csv'}
	# Attach recorder for waterheaters on/off
	tree[feeder.getMaxKey(tree)+1] = {'object':'group_recorder', 'group':'"class=waterheater"', 'property':'is_waterheater_on', 'interval':60, 'file':'allWaterheaterOn.csv'}
	# Attach recorder for waterheater tank temperatures
	tree[feeder.getMaxKey(tree)+1] = {'object':'group_recorder', 'group':'"class=waterheater"', 'property':'temperature', 'interval':60, 'file':'allWaterheaterTemp.csv'}
	
	# Attach recorders for system voltage map:
	stub = {'object':'group_recorder', 'group':'"class=node"', 'interval':60}
	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
	# Attach recorders for system voltage map, triplex:
	stub = {'object':'group_recorder', 'group':'"class=triplex_node"', 'interval':60}
	for phase in ['1','2']:
		copyStub = dict(stub)
		copyStub['property'] = 'voltage_' + phase
		copyStub['file'] = phase.lower() + 'nVoltDump.csv'
		tree[feeder.getMaxKey(tree) + 1] = copyStub
	# And get meters for system voltage map:
	stub = {'object':'group_recorder', 'group':'"class=triplex_meter"', 'interval':60}
	for phase in ['1','2']:
		copyStub = dict(stub)
		copyStub['property'] = 'voltage_' + phase
		copyStub['file'] = phase.lower() + 'mVoltDump.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))
	outData = {}
	# Std Err and Std Out
	outData['stderr'] = rawOut['stderr']
	outData['stdout'] = rawOut['stdout']
	# Time Stamps
	for key in rawOut:
		if '# timestamp' in rawOut[key]:
			outData['timeStamps'] = rawOut[key]['# timestamp']
			break
		elif '# property.. timestamp' in rawOut[key]:
			outData['timeStamps'] = rawOut[key]['# property.. timestamp']
		else:
			outData['timeStamps'] = []
	# Day/Month Aggregation Setup:
	stamps = outData.get('timeStamps',[])
	level = inputDict.get('simLengthUnits','hours')
	# Climate
	for key in rawOut:
		if key.startswith('Climate_') and key.endswith('.csv'):
			outData['climate'] = {}
			outData['climate']['Rain Fall (in/h)'] = hdmAgg(rawOut[key].get('rainfall'), sum, level)
			outData['climate']['Wind Speed (m/s)'] = hdmAgg(rawOut[key].get('wind_speed'), avg, level)
			outData['climate']['Temperature (F)'] = hdmAgg(rawOut[key].get('temperature'), max, level)
			outData['climate']['Snow Depth (in)'] = hdmAgg(rawOut[key].get('snowdepth'), max, level)
			outData['climate']['Direct Normal (W/sf)'] = hdmAgg(rawOut[key].get('solar_direct'), sum, level)
			#outData['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]
			outData['climate']['Global Horizontal (W/sm)']=climateWbySMList			
	# Voltage Band
	if 'VoltageJiggle.csv' in rawOut:
		outData['allMeterVoltages'] = {}
		outData['allMeterVoltages']['Min'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['min(voltage_12.mag)']], min, level)
		outData['allMeterVoltages']['Mean'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['mean(voltage_12.mag)']], avg, level)
		outData['allMeterVoltages']['StdDev'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['std(voltage_12.mag)']], avg, level)
		outData['allMeterVoltages']['Max'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['max(voltage_12.mag)']], max, level)
	# Power Consumption
	outData['Consumption'] = {}
	# Set default value to be 0, avoiding missing value when computing Loads
	outData['Consumption']['Power'] = [0] * int(inputDict["simLength"])
	outData['Consumption']['Losses'] = [0] * int(inputDict["simLength"])
	outData['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 outData['Consumption']:
				outData['Consumption']['Power'] = oneSwingPower
			else:
				outData['Consumption']['Power'] = vecSum(oneSwingPower,outData['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 outData['Consumption']:
				outData['Consumption']['DG'] = oneDgPower
			else:
				outData['Consumption']['DG'] = vecSum(oneDgPower,outData['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 outData['Consumption']:
				outData['Consumption']['DG'] = oneDgPower
			else:
				outData['Consumption']['DG'] = vecSum(oneDgPower,outData['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 outData['Consumption']:
				outData['Consumption']['Losses'] = oneLoss
			else:
				outData['Consumption']['Losses'] = vecSum(oneLoss,outData['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]
			outData[newkey] ={}
			outData[newkey]['RegTapA'] = [0] * int(inputDict["simLength"])
			outData[newkey]['RegTapB'] = [0] * int(inputDict["simLength"])
			outData[newkey]['RegTapC'] = [0] * int(inputDict["simLength"])
			outData[newkey]['RegTapA'] = rawOut[key]['tap_A']
			outData[newkey]['RegTapB'] = rawOut[key]['tap_B']
			outData[newkey]['RegTapC'] = rawOut[key]['tap_C']
			outData[newkey]['RegPhases'] = rawOut[key]['phases'][0]
		elif key.startswith('Capacitor_') and key.endswith('.csv'):
			capName=""
			capName = key
			newkey=capName.split(".")[0]
			outData[newkey] ={}
			outData[newkey]['Cap1A'] = [0] * int(inputDict["simLength"])
			outData[newkey]['Cap1B'] = [0] * int(inputDict["simLength"])
			outData[newkey]['Cap1C'] = [0] * int(inputDict["simLength"])
			outData[newkey]['Cap1A'] = rawOut[key]['switchA']
			outData[newkey]['Cap1B'] = rawOut[key]['switchB']
			outData[newkey]['Cap1C'] = rawOut[key]['switchC']
			outData[newkey]['CapPhases'] = rawOut[key]['phases'][0]

	# Print gridBallast Outputs to allOutputData.json
	outData['gridBallast'] = {}
	if 'allMeterPower.csv' in rawOut:
		outData['gridBallast']['totalNetworkLoad'] = [x / 1000 for x in rawOut.get('allMeterPower.csv')['sum(measured_real_power)']] #Convert W to kW
	if ('allZIPloadPower.csv' in rawOut) and ('allWaterheaterLoad.csv' in rawOut):
		outData['gridBallast']['availabilityMagnitude'] = [x[0] + x[1] for x in zip(rawOut.get('allWaterheaterLoad.csv')['sum(actual_load)'], rawOut.get('allZIPloadPower.csv')['sum(base_power)'])]
	if 'allZIPloadDemand.csv' in rawOut:
		outData['gridBallast']['ZIPloadDemand'] = {}
		for key in rawOut['allZIPloadDemand.csv']:
			if (key.startswith('ZIPload')) or (key.startswith('responsive')) or (key.startswith('unresponsive')):
				outData['gridBallast']['ZIPloadDemand'][key] = rawOut.get('allZIPloadDemand.csv')[key]
	if 'eachZIPloadPower.csv' in rawOut:
				outData['gridBallast']['ZIPloadPower'] = {}
				for key in rawOut['eachZIPloadPower.csv']:
					if (key.startswith('ZIPload')) or (key.startswith('responsive')) or (key.startswith('unresponsive')):
						outData['gridBallast']['ZIPloadPower'][key] = rawOut.get('eachZIPloadPower.csv')[key]
	if 'allWaterheaterOn.csv' in rawOut:
		outData['gridBallast']['waterheaterOn'] = {}
		for key in rawOut['allWaterheaterOn.csv']:
			if (key.startswith('waterheater')) or (key.startswith('waterHeater')):
				outData['gridBallast']['waterheaterOn'][key] = rawOut.get('allWaterheaterOn.csv')[key]
	if 'allWaterheaterTemp.csv' in rawOut:
		outData['gridBallast']['waterheaterTemp'] = {}
		for key in rawOut['allWaterheaterTemp.csv']:
			if (key.startswith('waterheater')) or (key.startswith('waterHeater')):
				outData['gridBallast']['waterheaterTemp'][key] = rawOut.get('allWaterheaterTemp.csv')[key]
	# System check - linux doesn't support newer GridLAB-D versions
	if sys.platform == 'linux2':
		pass
	else:
		outData['gridBallast']['penetrationLevel'] = 100*(gbWH+gbZIP)/(totalWH+totalZIP)
		# Frequency Player
		inArray = feederJson['attachments']['frequency.PLAYER'].split('\n')
		tempArray = []
		for each in inArray:
			x = each.split(',')
			y = float(x[1])
			tempArray.append(y)
		outData['frequencyPlayer'] = tempArray
	# EventTime calculations
	eventTime = inputDict['eventTime']
	eventLength = inputDict['eventLength'].split(':')
	eventDuration = datetime.timedelta(hours=int(eventLength[0]), minutes=int(eventLength[1]))
	eventStart = datetime.datetime.strptime(eventTime, '%Y-%m-%d %H:%M')
	eventEnd = eventStart + eventDuration
	outData['gridBallast']['eventStart'] = str(eventStart)
	outData['gridBallast']['eventEnd'] = str(eventEnd)
	outData['gridBallast']['xMin'] = str(eventStart - datetime.timedelta(minutes=30))
	outData['gridBallast']['xMax'] = str(eventEnd + datetime.timedelta(minutes=30))
	# Convert string to date
	# HACK: remove timezones, inconsistency in matching format
	timeStampsDebug = [x[:19] for x in outData['timeStamps']]
	dateTimeStamps = [datetime.datetime.strptime(x, '%Y-%m-%d %H:%M:%S') for x in timeStampsDebug]	
	eventEndIdx =  dateTimeStamps.index(eventEnd)
	# Recovery Time
	whOn = outData['gridBallast']['waterheaterOn']
	whOnList = whOn.values()
	whOnZip = zip(*whOnList)
	whOnSum = [sum(x) for x in whOnZip]
	anyOn = [x > 0 for x in whOnSum]
	tRecIdx = anyOn.index(True, eventEndIdx)
	tRec = dateTimeStamps[tRecIdx]
	recoveryTime = tRec - eventEnd
	outData['gridBallast']['recoveryTime'] = str(recoveryTime)
	# Waterheaters Off-Duration
	offDuration = tRec - eventStart
	outData['gridBallast']['offDuration'] = str(offDuration)
	# Reserve Magnitude (RM)
	availMag = outData['gridBallast']['availabilityMagnitude']
	totalNetLoad = outData['gridBallast']['totalNetworkLoad']
	availPerc = [100 * x[0]/x[1] for x in zip(availMag,totalNetLoad)]
	outData['gridBallast']['availabilityPercent'] = availPerc
	outData['gridBallast']['rm'] = [100 - x for x in availPerc]
	# Average RM during event
	eventRM = [100 - x[1] for x in zip(dateTimeStamps, availPerc) if (x[0] == eventStart) or (x[0] == eventEnd)]
	outData['gridBallast']['rmAvg'] = np.mean(eventRM)
	# Reserve Magnitude Variability Tolerance (RMVT)
	outData['gridBallast']['rmvt'] = np.std(eventRM)
	# Availability
	rmt = 7
	available = [x[1] > rmt for x in zip(dateTimeStamps, availPerc) if (x[0] < eventStart) or (x[0] > eventEnd)]
	outData['gridBallast']['availability'] = 100.0 * sum(available) / (int(inputDict['simLength']) - int(eventLength[1]) - 1)
	# Waterheater Temperature Drop calculations
	whTemp = outData['gridBallast']['waterheaterTemp']
	whTempList = whTemp.values()
	whTempZip = zip(*whTempList)
	whTempDrops = []
	LOWER_LIMIT_TEMP = 110 # Used for calculating quality of service. Typical hot shower temp = 105 F.
	for time in whTempZip:
		tempDrop = sum([t < LOWER_LIMIT_TEMP for t in time])
		whTempDrops.append(tempDrop)
	outData['gridBallast']['waterheaterTempDrops'] = whTempDrops
	# ZIPload calculations for Availability and QoS
	zPower = outData['gridBallast']['ZIPloadPower']
	zPowerList = zPower.values()
	zPowerZip = zip(*zPowerList)
	zDemand = outData['gridBallast']['ZIPloadDemand']
	zDemandList  = zDemand.values()
	zDemandZip = zip(*zDemandList)
	zDrops = []
	for x, y in zip(zPowerZip,zDemandZip):
		zDrop = 0
		for i in range(len(x)):
			if (x[i] == 0) and (y[i] > 0):
				zDrop += 1
		zDrops.append(zDrop)
	outData['gridBallast']['qualityDrops'] = [x + y for x, y in zip(zDrops, whTempDrops)]

	# 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)
	outData['genTime'] = genTime
	# Aggregate up the timestamps:
	if level=='days':
		outData['timeStamps'] = aggSeries(stamps, stamps, lambda x:x[0][0:10], 'days')
	elif level=='months':
		outData['timeStamps'] = aggSeries(stamps, stamps, lambda x:x[0][0:7], 'months')
	return outData
Exemple #11
0
def runForeground(modelDir, test_mode=False):
    ''' Run the model in its directory. WARNING: GRIDLAB CAN TAKE HOURS TO COMPLETE. '''
    with open(pJoin(modelDir, 'allInputData.json')) as f:
        inputDict = json.load(f)
    print("STARTING TO RUN", modelDir)
    beginTime = datetime.datetime.now()
    # 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 the names of the feeders from the .omd files:
    feederNames = [x[0:-4] for x in os.listdir(modelDir) if x.endswith(".omd")]
    for i, key in enumerate(feederNames):
        inputDict['feederName' + str(i + 1)] = feederNames[i]
    # Run GridLAB-D once for each feeder:
    for feederName in feederNames:
        try:
            os.remove(pJoin(modelDir, feederName, "allOutputData.json"))
        except Exception as 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"] = weather.zipCodeToClimateName(
            inputDict["zipCode"])
        shutil.copy(
            pJoin(_omfDir, "data", "Climate",
                  inputDict["climateName"] + ".tmy2"),
            pJoin(modelDir, feederName, "climate.tmy2"))
        try:
            startTime = datetime.datetime.now()
            with open(pJoin(modelDir, feederName, "feeder.omd")) as f:
                feederJson = json.load(f)
            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:
            if test_mode == True:
                raise 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)
    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)
    # Integrate data into allOutputData.json, if error happens, cancel it
    try:
        output = {}
        output["failures"] = {}
        numOfFeeders = 0
        for root, dirs, files in os.walk(modelDir):
            # dump error info into dict
            if "stderr.txt" in files:
                with open(pJoin(root, "stderr.txt"), "r") as stderrFile:
                    tempString = stderrFile.read()
                    if "ERROR" in tempString or "FATAL" in tempString or "Traceback" in tempString:
                        output["failures"]["feeder_" +
                                           str(os.path.split(root)[-1])] = {
                                               "stderr": tempString
                                           }
                        continue
            # dump simulated data into dict
            if "allOutputData.json" in files:
                with open(pJoin(root, "allOutputData.json"),
                          "r") as feederOutputData:
                    numOfFeeders += 1
                    feederOutput = json.load(feederOutputData)
                    # TODO: a better feeder name
                    output["feeder_" + str(os.path.split(root)[-1])] = {}
                    output["feeder_" +
                           str(os.path.split(root)[-1]
                               )]["Consumption"] = feederOutput["Consumption"]
                    output["feeder_" + str(os.path.split(root)[-1])][
                        "allMeterVoltages"] = feederOutput["allMeterVoltages"]
                    output["feeder_" + str(os.path.split(
                        root)[-1])]["stderr"] = feederOutput["stderr"]
                    output["feeder_" + str(os.path.split(
                        root)[-1])]["stdout"] = feederOutput["stdout"]
                    # output[root] = {feederOutput["Consumption"], feederOutput["allMeterVoltages"], feederOutput["stdout"], feederOutput["stderr"]}
        output["numOfFeeders"] = numOfFeeders
        output["timeStamps"] = feederOutput.get("timeStamps", [])
        output["climate"] = feederOutput.get("climate", [])
        # Add feederNames to output so allInputData feederName changes don't cause output rendering to disappear.
        for key, feederName in inputDict.items():
            if 'feederName' in key:
                output[key] = feederName
        with open(pJoin(modelDir, "allOutputData.json"), "w") as outFile:
            json.dump(output, outFile, indent=4)
        try:
            os.remove(pJoin(modelDir, "PPID.txt"))
        except:
            pass
        # Send email to user on model success.
        emailStatus = inputDict.get('emailStatus', 0)
        if (emailStatus == "on"):
            print("\n    EMAIL ALERT ON")
            email = session['user_id']
            try:
                with open("data/User/" + email + ".json") as f:
                    user = json.load(f)
                modelPath, modelName = pSplit(modelDir)
                message = "The model " + "<i>" + str(
                    modelName
                ) + "</i>" + " has successfully completed running. It ran for a total of " + str(
                    inputDict["runTime"]) + " seconds from " + str(
                        beginTime) + ", to " + str(finishTime) + "."
                return web.send_link(email, message, user)
            except Exception as e:
                print("ERROR: Failed sending model status email to user: "******", with exception: \n", e)
    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)
        # Send email to user on model failure.
        email = 'NoEmail'
        try:
            email = session['user_id']
            with open("data/User/" + email + ".json") as f:
                user = json.load(f)
            modelPath, modelName = pSplit(modelDir)
            message = "The model " + "<i>" + str(
                modelName
            ) + "</i>" + " has failed to complete running. It ran for a total of " + str(
                inputDict["runTime"]) + " seconds from " + str(
                    beginTime) + ", to " + str(finishTime) + "."
            return web.send_link(email, message, user)
        except Exception as e:
            print("Failed sending model status email to user: "******", with exception: \n", e)
Exemple #12
0
def run(modelDir, inputDict):
    ''' Run the model in its directory. '''
    try:
        # Set up GLM with correct time and recorders:
        omd = json.load(open(pJoin(modelDir, 'feeder.omd')))
        tree = omd.get('tree', {})
        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, 120, 'hours', '2011-01-01')
        # Run GridLAB-D
        startTime = dt.datetime.now()
        rawOut = gridlabd.runInFilesystem(tree,
                                          attachments=omd.get(
                                              'attachments', {}),
                                          workDir=modelDir)
        # Clean the output.
        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)'] = rawOut[key].get(
                    'rainfall')
                cleanOut['climate']['Wind Speed (m/s)'] = rawOut[key].get(
                    'wind_speed')
                cleanOut['climate']['Temperature (F)'] = rawOut[key].get(
                    'temperature')
                cleanOut['climate']['Snow Depth (in)'] = rawOut[key].get(
                    'snowdepth')
                cleanOut['climate']['Direct Normal (W/sf)'] = rawOut[key].get(
                    'solar_direct')
                climateWbySFList = rawOut[key].get('solar_global')
                #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'] = [
                float(i / 2)
                for i in rawOut['VoltageJiggle.csv']['min(voltage_12.mag)']
            ]
            cleanOut['allMeterVoltages']['Mean'] = [
                float(i / 2)
                for i in rawOut['VoltageJiggle.csv']['mean(voltage_12.mag)']
            ]
            cleanOut['allMeterVoltages']['StdDev'] = [
                float(i / 2)
                for i in rawOut['VoltageJiggle.csv']['std(voltage_12.mag)']
            ]
            cleanOut['allMeterVoltages']['Max'] = [
                float(i / 2)
                for i in rawOut['VoltageJiggle.csv']['max(voltage_12.mag)']
            ]
        # Dump the results.
        endTime = dt.datetime.now()
        inputDict["runTime"] = str(
            dt.timedelta(seconds=int((endTime - startTime).total_seconds())))
        with open(pJoin(modelDir, "allInputData.json"), "w") as inFile:
            json.dump(inputDict, inFile, indent=4)
        with open(pJoin(modelDir, "allOutputData.json"), "w") as outFile:
            json.dump(cleanOut, outFile, indent=4)
    except:
        # If input range wasn't valid delete output, write error to disk.
        cancel(modelDir)
        thisErr = traceback.format_exc()
        print 'ERROR IN MODEL', modelDir, thisErr
        inputDict['stderr'] = thisErr
        with open(os.path.join(modelDir, 'stderr.txt'), 'w') as errorFile:
            errorFile.write(thisErr)
        with open(pJoin(modelDir, "allInputData.json"), "w") as inFile:
            json.dump(inputDict, inFile, indent=4)
Exemple #13
0
def work(modelDir,inputDict):
	'''This reads a glm file, changes the method of powerflow and reruns'''
	feederName = [x for x in os.listdir(modelDir) if x.endswith('.omd')][0][:-4]
	inputDict['feederName1'] = feederName
	feederPath = pJoin(modelDir,feederName+'.omd')
	# Reads a pre-calibrated feeder.
	outData = {}
	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():
			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(inputDict['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]
	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'
	capstr = accum_cap[:-1]
	# 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(inputDict['simLengthHours'])
	simStartDate = inputDict['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']
		# if localTree[key].get('object','') == "capacitor":
		# 	time_delay_cap = localTree[key]['time_delay']
	#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()])
	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(inputDict.get('voltageNodes', 'IVVC1')),
	}
	#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])*(inputDict['wholesaleEnergyCostPerKwh'])*1000
	# lossSav = (whLosses[0]-whLosses[1])*inputDict['wholesaleEnergyCostPerKwh']*1000
	#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 = dt.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]
	#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)]
	for monthElement in simMonthList:
		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(inputDict['peakDemandCost'+str(monthToSeason[monthElement])+'PerKw'])
		lossRedDollars[monthElement] = (sum(realLoss[index1:index2])/1000.0 - sum(realLossnew[index1:index2])/1000.0)*(float(inputDict['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(inputDict['wholesaleEnergyCostPerKwh']) - float(inputDict['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]
	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(inputDict['omCost'])) * x - float(inputDict['capitalCost'])
	simplePayback = float(inputDict['capitalCost'])/(annualSavings - float(inputDict['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
	outData['timeStamps'] = timestamps
	outData['noCVRPower'] = p
	outData['withCVRPower'] = pnew
	outData['noCVRLoad'] = whLoads[0]
	outData['withCVRLoad'] = whLoads[1]
	outData['noCVRLosses'] = whLosses[0]
	outData['withCVRLosses'] = whLosses[1]
	outData['noCVRTaps'] = tap
	outData['withCVRTaps'] = tapnew
	outData['noCVRSubVolts'] = volt
	outData['withCVRSubVolts'] = voltnew
	outData['noCVRCapSwitch'] = switch
	outData['withCVRCapSwitch'] = switchnew
	outData['noCVRHighVolt'] = highVoltage
	outData['withCVRHighVolt'] = highVoltagenew
	outData['noCVRLowVolt'] = lowVoltage
	outData['withCVRLowVolt'] = lowVoltagenew
	outData['noCVRMeanVolt'] = meanVoltage
	outData['withCVRMeanVolt'] = meanVoltagenew
	#monetization
	outData['simMonthList'] = monShort
	outData['energyLostDollars'] = energyLostDollars
	outData['lossRedDollars'] = lossRedDollars
	outData['peakSaveDollars'] = peakSaveDollars
	outData['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 = dt.strptime(scadaDates[0].split(' PST')[0],"%Y-%m-%d %H:%M:%S")
		scadaEndDate = dt.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(inputDict.get('voltageNodes', 0)): voltageNodeExists = True
		if (beginRange > 0.0 or endRange < 0.0) and not housesExist:
			outData['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 outData.get('warnings','') != '':
				previousWarning = outData['warnings']
				outData['warnings'] = previousWarning + ' The voltage node: ' + str(inputDict.get('voltageNodes', 0)) + ' does not exist in the feeder.'
			else: outData['warnings'] = '<strong>WARNING:</strong> The voltage node <i>' + str(inputDict.get('voltageNodes', 0)) + '</i> does not exist in the feeder.'
	except:
		pass
	# # Update the runTime in the input file.
	# endTime = dt.now()
	# with open(pJoin(modelDir,"allInputData.json"),"w") as inFile:
	# 	json.dump(inputDict, inFile, indent=4)
	# with open(pJoin(modelDir,"outDataData.json"),"w") as outFile:
	# 	json.dump(outData, outFile, indent=4)
	# # For autotest, there won't be such file.
	# try:
	# 	os.remove(pJoin(modelDir, "PPID.txt"))
	# except Exception, e:
	# 	pass
	return outData
Exemple #14
0
def work(modelDir, inputDict):
	''' Run the model in its directory. WARNING: GRIDLAB CAN TAKE HOURS TO COMPLETE. '''
	# feederName = inputDict["feederName1"]
	feederName = [x for x in os.listdir(modelDir) if x.endswith('.omd')][0][:-4]
	inputDict["feederName1"] = feederName
	inputDict["climateName"] = zipCodeToClimateName(inputDict["zipCode"])
	shutil.copy(pJoin(__neoMetaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"),
		pJoin(modelDir, "climate.tmy2"))
	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"', 'interval':3600}
	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
	# Attach recorders for system voltage map, triplex:
	stub = {'object':'group_recorder', 'group':'"class=triplex_node"', 'interval':3600}
	for phase in ['1','2']:
		copyStub = dict(stub)
		copyStub['property'] = 'voltage_' + phase
		copyStub['file'] = phase.lower() + 'nVoltDump.csv'
		tree[feeder.getMaxKey(tree) + 1] = copyStub
	# Attach current recorder for overhead_lines
	currentStub = {'object':'group_recorder', 'group':'"class=overhead_line"', 'interval':3600}
	for phase in ['A','B','C']:
		copyCurrentStub = dict(currentStub)
		copyCurrentStub['property'] = 'current_out_' + phase
		copyCurrentStub['file'] = 'OH_line_current_phase' + phase + '.csv'
		tree[feeder.getMaxKey(tree) + 1] = copyCurrentStub
	rating_stub = {'object':'group_recorder', 'group':'"class=overhead_line"', 'interval':3600}
	copyRatingStub = dict(rating_stub)
	copyRatingStub['property'] = 'continuous_rating'
	copyRatingStub['file'] = 'OH_line_cont_rating.csv'
	tree[feeder.getMaxKey(tree) + 1] = copyRatingStub
	flow_stub = {'object':'group_recorder', 'group':'"class=overhead_line"', 'interval':3600}
	copyFlowStub = dict(flow_stub)
	copyFlowStub['property'] = 'flow_direction'
	copyFlowStub['file'] = 'OH_line_flow_direc.csv'
	tree[feeder.getMaxKey(tree) + 1] = copyFlowStub
	# Attach current recorder for underground_lines
	currentStubOH = {'object':'group_recorder', 'group':'"class=underground_line"', 'interval':3600}
	for phase in ['A','B','C']:
		copyCurrentStubOH = dict(currentStubOH)
		copyCurrentStubOH['property'] = 'current_out_' + phase
		copyCurrentStubOH['file'] = 'UG_line_current_phase' + phase + '.csv'
		tree[feeder.getMaxKey(tree) + 1] = copyCurrentStubOH
	ug_rating_stub = {'object':'group_recorder', 'group':'"class=underground_line"', 'interval':3600}
	copyUGRatingStub = dict(ug_rating_stub)
	copyUGRatingStub['property'] = 'continuous_rating'
	copyUGRatingStub['file'] = 'UG_line_cont_rating.csv'
	tree[feeder.getMaxKey(tree) + 1] = copyUGRatingStub
	ug_flow_stub = {'object':'group_recorder', 'group':'"class=underground_line"', 'interval':3600}
	ugCopyFlowStub = dict(ug_flow_stub)
	ugCopyFlowStub['property'] = 'flow_direction'
	ugCopyFlowStub['file'] = 'UG_line_flow_direc.csv'
	tree[feeder.getMaxKey(tree) + 1] = ugCopyFlowStub
	# And get meters for system voltage map:
	stub = {'object':'group_recorder', 'group':'"class=triplex_meter"', 'interval':3600}
	for phase in ['1','2']:
		copyStub = dict(stub)
		copyStub['property'] = 'voltage_' + phase
		copyStub['file'] = phase.lower() + 'mVoltDump.csv'
		tree[feeder.getMaxKey(tree) + 1] = copyStub
	for key in tree:
		if 'bustype' in tree[key].keys():
			if tree[key]['bustype'] == 'SWING':
				tree[key]['object'] = 'meter'
				swingN = tree[key]['name']
	swingRecord = {'object':'recorder', 'property':'voltage_A,measured_real_power,measured_power','file':'subVoltsA.csv','parent':swingN, 'interval':60}
	tree[feeder.getMaxKey(tree) + 1] = swingRecord
	for key in tree:
		if 'omftype' in tree[key].keys() and tree[key]['argument']=='minimum_timestep=3600':
			tree[key]['argument'] = 'minimum_timestep=60'
	# If there is a varvolt object in the tree, add recorder to swingbus and node from voltage_measurements property
	# Find var_volt object
	downLineNode = 'None'
	for key in tree:
		if 'object' in tree[key].keys() and tree[key]['object']=='volt_var_control':
			downLineNode = tree[key]['voltage_measurements']
	if downLineNode != 'None':
		downNodeRecord = {'object':'recorder', 'property':'voltage_A','file':'firstDownlineVoltsA.csv','parent':downLineNode, 'interval':60}
		tree[feeder.getMaxKey(tree) + 1] = downNodeRecord
	# Violation recorder to display to users 
	# violationRecorder = {'object':'violation_recorder','node_continuous_voltage_limit_lower':0.95,'file':'Violation_Log.csv',
	# 					'secondary_dist_voltage_rise_lower_limit':-0.042,'substation_pf_lower_limit':0.85,'substation_breaker_C_limit':300,
	# 					'secondary_dist_voltage_rise_upper_limit':0.025,'substation_breaker_B_limit':300,'violation_flag':'ALLVIOLATIONS',
	# 					'node_instantaneous_voltage_limit_upper':1.1, 'inverter_v_chng_per_interval_lower_bound':-0.05, 'virtual_substation':swingN,
	# 					'substation_breaker_A_limit':300, 'xfrmr_thermal_limit_lower':0,'node_continuous_voltage_interval':300,'strict':'false',
	# 					'node_instantaneous_voltage_limit_lower':0,'line_thermal_limit_upper':1,'echo':'false','node_continuous_voltage_limit_upper':1.05,
	# 					'interval':30,'line_thermal_limit_lower':0,'summary':'Violation_Summary.csv','inverter_v_chng_interval':60,
	# 					'xfrmr_thermal_limit_upper':2,'inverter_v_chng_per_interval_upper_bound':0.050}
	# tree[feeder.getMaxKey(tree) + 1] = violationRecorder
	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))
		# voltDumps have no values when gridlabD fails or the files dont exist
	if not os.path.isfile(pJoin(modelDir,'aVoltDump.csv')):
		with open (pJoin(modelDir,'stderr.txt')) as inFile:
			stdErrText = inFile.read()
		message = 'GridLAB-D crashed. Error log:\n' + stdErrText
		raise Exception(message)
	elif len(rawOut['aVoltDump.csv']['# timestamp']) == 0:
		with open (pJoin(modelDir,'stderr.txt')) as inFile:
			stdErrText = inFile.read()
		message = 'GridLAB-D crashed. Error log:\n' + stdErrText
		raise Exception(message)
	outData = {}
	# Std Err and Std Out
	outData['stderr'] = rawOut['stderr']
	outData['stdout'] = rawOut['stdout']
	# Time Stamps
	for key in rawOut:
		if '# timestamp' in rawOut[key]:
			outData['timeStamps'] = rawOut[key]['# timestamp']
			break
		elif '# property.. timestamp' in rawOut[key]:
			outData['timeStamps'] = rawOut[key]['# property.. timestamp']
		else:
			outData['timeStamps'] = []
	# Day/Month Aggregation Setup:
	stamps = outData.get('timeStamps',[])
	level = inputDict.get('simLengthUnits','hours')
	# Climate
	for key in rawOut:
		if key.startswith('Climate_') and key.endswith('.csv'):
			outData['climate'] = {}
			outData['climate']['Rain Fall (in/h)'] = hdmAgg(rawOut[key].get('rainfall'), sum, level)
			outData['climate']['Wind Speed (m/s)'] = hdmAgg(rawOut[key].get('wind_speed'), avg, level)
			outData['climate']['Temperature (F)'] = hdmAgg(rawOut[key].get('temperature'), max, level)
			outData['climate']['Snow Depth (in)'] = hdmAgg(rawOut[key].get('snowdepth'), max, level)
			outData['climate']['Direct Normal (W/sf)'] = hdmAgg(rawOut[key].get('solar_direct'), sum, level)
			#outData['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]
			outData['climate']['Global Horizontal (W/sm)']=climateWbySMList			
	# Voltage Band
	if 'VoltageJiggle.csv' in rawOut:
		outData['allMeterVoltages'] = {}
		outData['allMeterVoltages']['Min'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['min(voltage_12.mag)']], min, level)
		outData['allMeterVoltages']['Mean'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['mean(voltage_12.mag)']], avg, level)
		outData['allMeterVoltages']['StdDev'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['std(voltage_12.mag)']], avg, level)
		outData['allMeterVoltages']['Max'] = hdmAgg([float(i / 2) for i in rawOut['VoltageJiggle.csv']['max(voltage_12.mag)']], max, level)
	# Power Consumption
	outData['Consumption'] = {}
	# Set default value to be 0, avoiding missing value when computing Loads
	outData['Consumption']['Power'] = [0] * int(inputDict["simLength"])
	outData['Consumption']['Losses'] = [0] * int(inputDict["simLength"])
	outData['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 outData['Consumption']:
				outData['Consumption']['Power'] = oneSwingPower
			else:
				outData['Consumption']['Power'] = vecSum(oneSwingPower,outData['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 outData['Consumption']:
				outData['Consumption']['DG'] = oneDgPower
			else:
				outData['Consumption']['DG'] = vecSum(oneDgPower,outData['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 outData['Consumption']:
				outData['Consumption']['DG'] = oneDgPower
			else:
				outData['Consumption']['DG'] = vecSum(oneDgPower,outData['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 outData['Consumption']:
				outData['Consumption']['Losses'] = oneLoss
			else:
				outData['Consumption']['Losses'] = vecSum(oneLoss,outData['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]
			outData[newkey] ={}
			outData[newkey]['RegTapA'] = [0] * int(inputDict["simLength"])
			outData[newkey]['RegTapB'] = [0] * int(inputDict["simLength"])
			outData[newkey]['RegTapC'] = [0] * int(inputDict["simLength"])
			outData[newkey]['RegTapA'] = rawOut[key]['tap_A']
			outData[newkey]['RegTapB'] = rawOut[key]['tap_B']
			outData[newkey]['RegTapC'] = rawOut[key]['tap_C']
			outData[newkey]['RegPhases'] = rawOut[key]['phases'][0]
		elif key.startswith('Capacitor_') and key.endswith('.csv'):
			capName=""
			capName = key
			newkey=capName.split(".")[0]
			outData[newkey] ={}
			outData[newkey]['Cap1A'] = [0] * int(inputDict["simLength"])
			outData[newkey]['Cap1B'] = [0] * int(inputDict["simLength"])
			outData[newkey]['Cap1C'] = [0] * int(inputDict["simLength"])
			outData[newkey]['Cap1A'] = rawOut[key]['switchA']
			outData[newkey]['Cap1B'] = rawOut[key]['switchB']
			outData[newkey]['Cap1C'] = rawOut[key]['switchC']
			outData[newkey]['CapPhases'] = rawOut[key]['phases'][0]
	# Capture voltages at the swingbus
	# Loop through voltDump for swingbus voltages
	subData = []
	downData = []
	with open(pJoin(modelDir,"subVoltsA.csv")) as subFile:
		reader = csv.reader(subFile)
		subData = [x for x in reader]
	if downLineNode != 'None':
		with open(pJoin(modelDir,"firstDownlineVoltsA.csv")) as downFile:
			reader = csv.reader(downFile)
			downData = [x for x in reader]
	FIRST_DATA_ROW = 9
	cleanDown = [stringToMag(x[1]) for x in downData[FIRST_DATA_ROW:-1]]
	swingTimestamps = [x[0] for x in subData[FIRST_DATA_ROW:-1]]
	cleanSub = [stringToMag(x[1]) for x in subData[FIRST_DATA_ROW:-1]]
	# real_power / power
	powerFactors = []
	for row in subData[FIRST_DATA_ROW:-1]:
		powerFactors.append(abs(float(row[2])/stringToMag(row[3])))
	outData['powerFactors'] = powerFactors
	outData['swingVoltage'] = cleanSub
	outData['downlineNodeVolts'] = cleanDown
	outData['swingTimestamps'] = swingTimestamps
	# If there is a var volt system, find the min and max voltage for a band
	minVoltBand = []
	maxVoltBand = []
	if downLineNode != 'None':
		for key in tree:
			objKeys = tree[key].keys()
			if 'object' in objKeys:
				if tree[key]['object']=='volt_var_control':
					minVoltBand.append(float(tree[key]['minimum_voltages']))
					maxVoltBand.append(float(tree[key]['maximum_voltages']))
		outData['minVoltBand'] = minVoltBand
		outData['maxVoltBand'] = maxVoltBand
	# Violation Summary and Log
	# violationData = ''
	# violationArray = []
	# with open(pJoin(modelDir,"Violation_Summary.csv")) as vioSum:
	# 	reader = csv.reader(vioSum)
	# 	for row in reader:
	# 		violationArray.append(row)	
	# for row in violationArray[4:]:
	# 	violationData += str(' '.join(row)) + "\n"
	# outData["violationSummary"] = violationData
	# violationLogArray = []
	# violationLog = ''
	# with open(pJoin(modelDir,"Violation_Log.csv")) as vioLog:
	# 	logger = csv.reader(vioLog)
	# 	for row in logger:
	# 		violationLogArray.append(row)
	# for row in violationLogArray[6:]:
	# 	violationLog += str(' '.join(row)) + "\n"
	# outData['violationLog'] = violationLog
	# 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, mapTimestamp = generateVoltChart(tree, rawOut, modelDir, neatoLayout=doNeato)
	outData['genTime'] = genTime
	outData['mapTimestamp'] = mapTimestamp
	# Aggregate up the timestamps:
	if level=='days':
		outData['timeStamps'] = aggSeries(stamps, stamps, lambda x:x[0][0:10], 'days')
	elif level=='months':
		outData['timeStamps'] = aggSeries(stamps, stamps, lambda x:x[0][0:7], 'months')
	return outData
Exemple #15
0
def runForeground(modelDir, inData, fs):
    '''This reads a glm file, changes the method of powerflow and reruns'''
    try:
        startTime = datetime.now()
        # calibrate and run cvrdynamic

        feederPath = pJoin("data", "Feeder", inData[
                           "feederName"].split("___")[0], inData["feederName"].split("___")[1] + '.json')
        fs.export_from_fs_to_local(feederPath, feederPath)
        scadaPath = pJoin("uploads", (inData["scadaFile"] + '.tsv'))
        fs.export_from_fs_to_local(scadaPath, scadaPath)
        omf.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)
        Plot.save_fig(plt, 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)
        Plot.save_fig(plt, 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)
        Plot.save_fig(plt, 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')
        Plot.save_fig(plt, 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()
        Plot.save_fig(plt, 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()
        Plot.save_fig(plt, 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()
        Plot.save_fig(plt, 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 ($)')
        Plot.save_fig(plt, 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')
        Plot.save_fig(plt, 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())))
        fs.save(pJoin(modelDir, "allInputData.json"), json.dumps(inData, indent=4))
        fs.save(pJoin(modelDir, "allOutputData.json"), json.dumps(allOutput, 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
Exemple #16
0
def runForeground(modelDir, inputDict, fs):
    """ Run the model in its directory. WARNING: GRIDLAB CAN TAKE HOURS TO COMPLETE. """
    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"))
                fs.remove(pJoin(modelDir, feederName, "allOutputData.json"))
            except Exception, e:
                pass
            if not os.path.isdir(pJoin(modelDir, feederName)):
                # create subfolders for feeders
                os.makedirs(pJoin(modelDir, feederName))

            fs.export_from_fs_to_local(
                pJoin("data", "Feeder", feederDir, feederName + ".json"), pJoin(modelDir, feederName, "feeder.json")
            )
            inputDict["climateName"], latforpvwatts = zipCodeToClimateName(inputDict["zipCode"], fs)
            fs.export_from_fs_to_local(
                pJoin("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"],
                )
                if "attachments" in feederJson:
                    attachments = feederJson["attachments"]
                else:
                    attachments = []
                # RUN GRIDLABD IN FILESYSTEM (EXPENSIVE!)
                rawOut = gridlabd.runInFilesystem(
                    tree, attachments=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, stamps
                        )
                        cleanOut["climate"]["Wind Speed (m/s)"] = hdmAgg(
                            rawOut[key].get("wind_speed"), avg, level, stamps
                        )
                        cleanOut["climate"]["Temperature (F)"] = hdmAgg(
                            rawOut[key].get("temperature"), max, level, stamps
                        )
                        cleanOut["climate"]["Snow Depth (in)"] = hdmAgg(
                            rawOut[key].get("snowdepth"), max, level, stamps
                        )
                        cleanOut["climate"]["Direct Insolation (W/m^2)"] = hdmAgg(
                            rawOut[key].get("solar_direct"), sum, level, stamps
                        )
                # 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, stamps
                    )
                    cleanOut["allMeterVoltages"]["Mean"] = hdmAgg(
                        [float(i / 2) for i in rawOut["VoltageJiggle.csv"]["mean(voltage_12.mag)"]], avg, level, stamps
                    )
                    cleanOut["allMeterVoltages"]["StdDev"] = hdmAgg(
                        [float(i / 2) for i in rawOut["VoltageJiggle.csv"]["std(voltage_12.mag)"]], avg, level, stamps
                    )
                    cleanOut["allMeterVoltages"]["Max"] = hdmAgg(
                        [float(i / 2) for i in rawOut["VoltageJiggle.csv"]["max(voltage_12.mag)"]], max, level, stamps
                    )
                # 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,
                            stamps,
                        )
                        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,
                            stamps,
                        )
                        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, stamps)]
                        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,
                            stamps,
                        )
                        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)
Exemple #17
0
def omfCalibrate(workDir,
                 feederPath,
                 scadaPath,
                 simStartDate,
                 simLength,
                 simLengthUnits,
                 solver="FBS",
                 calibrateError=(0.05, 5),
                 trim=5):
    '''calibrates a feeder and saves the calibrated tree at a location.
	Note: feeders with cap banks should be calibrated with cap banks OPEN.
	We have seen cap banks throw off calibration.'''
    with open(feederPath, "r") as jsonIn:
        feederJson = json.load(jsonIn)
        tree = feederJson.get("tree", {})
    simLength = simLength + trim
    # Process scada data.
    scadaSubPower = _processScadaData(pJoin(workDir, "gridlabD"), scadaPath,
                                      simStartDate, simLengthUnits)
    # Load specified solver.
    for key in tree:
        if tree[key].get("module", "").lower() == "powerflow":
            tree[key] = {"module": "powerflow", "solver_method": solver}
    # Attach player.
    classOb = {'omftype': 'class player', 'argument': '{double value;}'}
    playerOb = {
        "object": "player",
        "property": "value",
        "name": "scadaLoads",
        "file": "subScada.player",
        "loop": "0"
    }
    maxKey = feeder.getMaxKey(tree)
    playerKey = maxKey + 2
    tree[maxKey + 1] = classOb
    tree[playerKey] = playerOb
    # Make loads reference player.
    loadTemplate = {
        "object": "triplex_load",
        "power_pf_12": "0.95",
        "impedance_pf_12": "0.98",
        "power_pf_12": "0.90",
        "impedance_fraction_12": "0.7",
        "power_fraction_12": "0.3"
    }
    loadTemplateR = {
        "object": "load",
        "impedance_pf_A": "0.98",
        "impedance_pf_B": "0.98",
        "impedance_pf_C": "0.98",
        "power_pf_A": "0.90",
        "power_pf_B": "0.90",
        "power_pf_C": "0.90",
        "impedance_fraction_A": "0.7",
        "impedance_fraction_B": "0.7",
        "impedance_fraction_C": "0.7",
        "power_fraction_A": "0.3",
        "power_fraction_B": "0.3",
        "power_fraction_C": "0.3"
    }
    for key in tree:
        ob = tree[key]
        if ob.get("object", "") in ("triplex_node", "triplex_load") and (
                ob.get("power_12") or ob.get("base_power_12")):
            # Add to triplex_nodes.
            newOb = dict(loadTemplate)
            newOb["name"] = ob.get("name", "")
            newOb["parent"] = ob.get("parent", "")
            newOb["phases"] = ob.get("phases", "")
            newOb["nominal_voltage"] = ob.get("nominal_voltage", "")
            newOb["latitude"] = ob.get("latitude", "0")
            newOb["longitude"] = ob.get("longitude", "0")
            oldPow = ob.get("power_12", "").replace("j", "d")
            if not oldPow:
                oldPow = ob.get("base_power_12")
                if "scadaloads.value*" in oldPow:
                    oldPow = oldPow[17:]
            pythagPower = gridlabd._strClean(oldPow)
            newOb["base_power_12"] = "scadaLoads.value*" + str(pythagPower)
            tree[key] = newOb
        elif ob.get("object", "") == "load":
            # Add to residential_loads too.
            newOb = dict(loadTemplateR)
            newOb["name"] = ob.get("name", "")
            newOb["parent"] = ob.get("parent", "")
            newOb["phases"] = ob.get("phases", "")
            newOb["load_class"] = ob.get("load_class", "")
            newOb["nominal_voltage"] = ob.get("nominal_voltage", "")
            newOb["latitude"] = ob.get("latitude", "0")
            newOb["longitude"] = ob.get("longitude", "0")
            try:
                oldPow = ob.get("constant_power_A", "").replace("j", "d")
                pythagPower = gridlabd._strClean(oldPow)
                newOb["base_power_A"] = "scadaLoads.value*" + str(pythagPower)
            except:
                pass
            try:
                oldPow = ob.get("constant_power_B", "").replace("j", "d")
                pythagPower = gridlabd._strClean(oldPow)
                newOb["base_power_B"] = "scadaLoads.value*" + str(pythagPower)
            except:
                pass
            try:
                oldPow = ob.get("constant_power_C", "").replace("j", "d")
                pythagPower = gridlabd._strClean(oldPow)
                newOb["base_power_C"] = "scadaLoads.value*" + str(pythagPower)
            except:
                pass
            tree[key] = newOb
    # Convert swing bus to a meter.
    for key in tree:
        if tree[key].get('bustype', '').lower() == 'swing' and tree[key].get(
                'object', '') != 'meter':
            swingName = tree[key].get('name')
            regIndex = key
            tree[key]['object'] = 'meter'
    # Search for the substation meter and attach a recorder there.
    for key in tree:
        if tree[key].get('bustype', '').lower() == 'swing':
            swingName = tree[key].get('name')
    recOb = {
        "object": "recorder",
        "parent": swingName,
        "property":
        "measured_real_power,measured_reactive_power,measured_power",
        "file": "caliSub.csv",
        "interval": "3600"
    }
    outputRecorderKey = maxKey + 3
    tree[outputRecorderKey] = recOb
    feeder.adjustTime(tree, simLength, simLengthUnits,
                      simStartDate['Date'].strftime("%Y-%m-%d %H:%M:%S"))

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

    outRealPow, outRealPowIter, lastFile, iteration = runPowerflowIter(
        tree, scadaSubPower[trim:simLength])
    caliPowVectors = [[
        float(element) for element in scadaSubPower[trim:simLength]
    ], [float(element) / 1000 for element in outRealPow],
                      [float(element) / 1000 for element in outRealPowIter]]
    labels = ["scadaSubPower", "initialGuess", "finalGuess"]
    colors = ['red', 'lightblue', 'blue']
    chartData = {
        "Title":
        "Substation Calibration Check (Iterated " + str(iteration + 1) + "X)",
        "fileName": "caliCheckPlot",
        "colors": colors,
        "labels": labels,
        "timeZone": simStartDate['timeZone']
    }
    # Trimming vectors to make them all the same length as the smallest vector
    minCaliPowVecLen = min(len(caliPowVectors[0]), len(caliPowVectors[1]),
                           len(caliPowVectors[2]))
    caliPowVectors[0] = caliPowVectors[0][:minCaliPowVecLen]
    caliPowVectors[1] = caliPowVectors[1][:minCaliPowVecLen]
    caliPowVectors[2] = caliPowVectors[2][:minCaliPowVecLen]
    print "Len:", len(caliPowVectors[0]), len(caliPowVectors[1]), len(
        caliPowVectors[2])
    plotLine(workDir, caliPowVectors, chartData,
             simStartDate['Date'] + dt.timedelta(hours=trim), simLengthUnits)
    # Write the final output.
    with open(pJoin(workDir, "calibratedFeeder.omd"), "w") as outJson:
        playerString = open(pJoin(pJoin(workDir, "gridlabD"), lastFile)).read()
        feederJson["attachments"][lastFile] = playerString
        feederJson["tree"] = tree
        json.dump(feederJson, outJson, indent=4)
    return
Exemple #18
0
def runForeground(modelDir):
	''' Run the model in its directory. WARNING: GRIDLAB CAN TAKE HOURS TO COMPLETE. '''
	inputDict = json.load(open(pJoin(modelDir, 'allInputData.json')))
	print "STARTING TO RUN", modelDir
	beginTime = datetime.datetime.now()
	# 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 the names of the feeders from the .omd files:
	feederNames = [x[0:-4] for x in os.listdir(modelDir) if x.endswith(".omd")]
	for i, key in enumerate(feederNames):
		inputDict['feederName' + str(i + 1)] = feederNames[i]
	# Run GridLAB-D once for each feeder:
	for feederName in feederNames:
		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"] = zipCodeToClimateName(inputDict["zipCode"])
		shutil.copy(pJoin(_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)
Exemple #19
0
def main():
	''' JSON manipulation, Gridlab running, etc. goes here. '''
	# Import data.
	feedJson = json.load(open('./ABEC Frank Calibrated.json'))
	tree = feedJson['tree']
	# Input data, model-style.
	inputDict = {'simLength':24,'simStartDate':'2011-01-01', 'simLengthUnits':'hours'}
	# Add recorders.
	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[omf.feeder.getMaxKey(tree) + 1] = copyStub
	feeder.adjustTime(tree, inputDict['simLength'], inputDict['simLengthUnits'], inputDict['simStartDate'])
	# Run gridlab.
	allOutputData = runInFilesystem(tree, attachments=feedJson['attachments'], keepFiles=True, workDir='.', glmName='ABEC Frank SolverGen.glm')
	try: os.remove('PID.txt')
	except: pass
	print 'Gridlab ran correctly', allOutputData.keys()
	# Make plots.
	#TODO: figure out what to do about neato taking like 2 minutes to run.
	neatoLayout = True
	# 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))
	# Make a graph object.
	fGraph = omf.feeder.treeToNxGraph(tree)
	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}
	# Plot all time steps.
	for step, stamp in enumerate(allOutputData['aVoltDump.csv']['# timestamp']):
		# Build voltage map.
		nodeVolts = {}
		for nodeName in [x for x in allOutputData['aVoltDump.csv'].keys() if x != '# timestamp']:
			allVolts = []
			for phase in ['A','B','C']:
				v = complex(allOutputData[phase.lower() + 'VoltDump.csv'][nodeName][step])
				phaseVolt = _pythag(v.real, v.imag)
				if phaseVolt != 0.0:
					if _digits(phaseVolt)>3:
						# Normalize to 120 V standard
						phaseVolt = phaseVolt*(120/feedVoltage)
					allVolts.append(phaseVolt)
			# HACK: Take average of all phases to collapse dimensionality.
			nodeVolts[nodeName] = _avg(allVolts)
		# Apply voltage map and chart it.
		voltChart = plt.figure(figsize=(10,10))
		plt.axes(frameon = 0)
		plt.axis('off')
		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()
		plt.title(stamp)
		voltChart.savefig('./pngs/volts' + str(step).zfill(3) + '.png')
		# Reclaim memory by closing, deleting and garbage collecting the last chart.
		voltChart.clf()
		plt.close()
		del voltChart
		gc.collect()