Ejemplo n.º 1
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)
Ejemplo n.º 2
0
def runForeground(modelDir, inputDict, fs):
    ''' Run the model in the foreground. WARNING: can take about a minute. '''
    # Global vars, and load data from the model directory.
    print "STARTING TO RUN", modelDir
    try:
        startTime = datetime.datetime.now()
        feederJson = json.load(open(pJoin(modelDir, "feeder.json")))
        tree = feederJson.get("tree", {})
        attachments = feederJson.get("attachments", {})
        allOutput = {}
        ''' Run CVR analysis. '''
        # Reformate monthData and rates.
        rates = {k: float(inputDict[k]) for k in ["capitalCost", "omCost", "wholesaleEnergyCostPerKwh",
                                                  "retailEnergyCostPerKwh", "peakDemandCostSpringPerKw", "peakDemandCostSummerPerKw",
                                                  "peakDemandCostFallPerKw", "peakDemandCostWinterPerKw"]}
        # print "RATES", rates
        monthNames = ["January", "February", "March", "April", "May", "June", "July", "August",
                      "September", "October", "November", "December"]
        monthToSeason = {'January': 'Winter', 'February': 'Winter', 'March': 'Spring', 'April': 'Spring',
                         'May': 'Spring', 'June': 'Summer', 'July': 'Summer', 'August': 'Summer',
                         'September': 'Fall', 'October': 'Fall', 'November': 'Fall', 'December': 'Winter'}
        monthData = []
        for i, x in enumerate(monthNames):
            monShort = x[0:3].lower()
            season = monthToSeason[x]
            histAvg = float(inputDict.get(monShort + "Avg", 0))
            histPeak = float(inputDict.get(monShort + "Peak", 0))
            monthData.append({"monthId": i, "monthName": x, "histAverage": histAvg,
                              "histPeak": histPeak, "season": season})
        # for row in monthData:
        # 	print row
        # Graph the SCADA data.
        fig = plt.figure(figsize=(10, 6))
        indices = [r['monthName'] for r in monthData]
        d1 = [r['histPeak'] / (10**3) for r in monthData]
        d2 = [r['histAverage'] / (10**3) for r in monthData]
        ticks = range(len(d1))
        bar_peak = plt.bar(ticks, d1, color='gray')
        bar_avg = plt.bar(ticks, d2, color='dimgray')
        plt.legend([bar_peak[0], bar_avg[0]], ['histPeak', 'histAverage'], bbox_to_anchor=(0., 1.015, 1., .102), loc=3,
                   ncol=2, mode="expand", borderaxespad=0.1)
        plt.xticks([t + 0.5 for t in ticks], indices)
        plt.ylabel('Mean and peak historical power consumptions (kW)')
        fig.autofmt_xdate()
        Plot.save_fig(plt, pJoin(modelDir, "scadaChart.png"))
        allOutput["histPeak"] = d1
        allOutput["histAverage"] = d2
        allOutput["monthName"] = [name[0:3] for name in monthNames]
        # Graph feeder.
        fig = plt.figure(figsize=(10, 10))
        myGraph = omf.feeder.treeToNxGraph(tree)
        omf.feeder.latLonNxGraph(myGraph, neatoLayout=False)
        Plot.save_fig(plt, pJoin(modelDir, "feederChart.png"))
        with open(pJoin(modelDir, "feederChart.png"), "rb") as inFile:
            allOutput["feederChart"] = inFile.read().encode("base64")
        # Get the load levels we need to test.
        allLoadLevels = [x.get(
            'histPeak', 0) for x in monthData] + [y.get('histAverage', 0) for y in monthData]
        maxLev = _roundOne(max(allLoadLevels), 'up')
        minLev = _roundOne(min(allLoadLevels), 'down')
        tenLoadLevels = range(
            int(minLev), int(maxLev), int((maxLev - minLev) / 10))
        # Gather variables from the feeder.
        for key in tree.keys():
            # Set clock to single timestep.
            if tree[key].get('clock', '') == 'clock':
                tree[key] = {"timezone": "PST+8PDT",
                             "stoptime": "'2013-01-01 00:00:00'",
                             "starttime": "'2013-01-01 00:00:00'",
                             "clock": "clock"}
            # Save swing node index.
            if tree[key].get('bustype', '').lower() == 'swing':
                swingIndex = key
                swingName = tree[key].get('name')
            # Remove all includes.
            if tree[key].get('omftype', '') == '#include':
                del key
        # Find the substation regulator and config.
        for key in tree:
            if tree[key].get('object', '') == 'regulator' and tree[key].get('from', '') == swingName:
                regIndex = key
                regConfName = tree[key]['configuration']
        for key in tree:
            if tree[key].get('name', '') == regConfName:
                regConfIndex = key
        # Set substation regulator to manual operation.
        # GLOBAL VARIABLE FOR DEFAULT TAP POSITION
        baselineTap = int(inputDict.get("baselineTap"))
        tree[regConfIndex] = {
            'name': tree[regConfIndex]['name'],
            'object': 'regulator_configuration',
            'connect_type': '1',
            'raise_taps': '10',
            'lower_taps': '10',
            'CT_phase': 'ABC',
            'PT_phase': 'ABC',
            # Yo, 0.10 means at tap_pos 10 we're 10% above 120V.
            'regulation': '0.10',
            'Control': 'MANUAL',
            'control_level': 'INDIVIDUAL',
            'Type': 'A',
            'tap_pos_A': str(baselineTap),
            'tap_pos_B': str(baselineTap),
            'tap_pos_C': str(baselineTap)}
        # Attach recorders relevant to CVR.
        recorders = [
            {'object': 'collector',
             'file': 'ZlossesTransformer.csv',
             'group': 'class=transformer',
             'limit': '0',
             'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
            {'object': 'collector',
             'file': 'ZlossesUnderground.csv',
             'group': 'class=underground_line',
             'limit': '0',
             'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
            {'object': 'collector',
             'file': 'ZlossesOverhead.csv',
             'group': 'class=overhead_line',
             'limit': '0',
             'property': 'sum(power_losses_A.real),sum(power_losses_A.imag),sum(power_losses_B.real),sum(power_losses_B.imag),sum(power_losses_C.real),sum(power_losses_C.imag)'},
            {'object': 'recorder',
             'file': 'Zregulator.csv',
             'limit': '0',
             'parent': tree[regIndex]['name'],
             'property': 'tap_A,tap_B,tap_C,power_in.real,power_in.imag'},
            {'object': 'collector',
             'file': 'ZvoltageJiggle.csv',
             'group': 'class=triplex_meter',
             'limit': '0',
             'property': 'min(voltage_12.mag),mean(voltage_12.mag),max(voltage_12.mag),std(voltage_12.mag)'},
            {'object': 'recorder',
             'file': 'ZsubstationTop.csv',
             'limit': '0',
             'parent': tree[swingIndex]['name'],
             'property': 'voltage_A,voltage_B,voltage_C'},
            {'object': 'recorder',
             'file': 'ZsubstationBottom.csv',
             'limit': '0',
             'parent': tree[regIndex]['to'],
             'property': 'voltage_A,voltage_B,voltage_C'}]
        biggest = 1 + max([int(k) for k in tree.keys()])
        for index, rec in enumerate(recorders):
            tree[biggest + index] = rec
        # Change constant PF loads to ZIP loads. (See evernote for rationale
        # about 50/50 power/impedance mix.)
        blankZipModel = {'object': 'triplex_load',
                         'name': 'NAMEVARIABLE',
                         'base_power_12': 'POWERVARIABLE',
                         'power_fraction_12': str(inputDict.get("p_percent")),
                         'impedance_fraction_12': str(inputDict.get("z_percent")),
                         'current_fraction_12': str(inputDict.get("i_percent")),
                         # MAYBEFIX: we can probably get this PF data from the
                         # Milsoft loads.
                         'power_pf_12': str(inputDict.get("power_factor")),
                         'impedance_pf_12': str(inputDict.get("power_factor")),
                         'current_pf_12': str(inputDict.get("power_factor")),
                         'nominal_voltage': '120',
                         'phases': 'PHASESVARIABLE',
                         'parent': 'PARENTVARIABLE'}

        def powerClean(powerStr):
            ''' take 3339.39+1052.29j to 3339.39 '''
            return powerStr[0:powerStr.find('+')]
        for key in tree:
            if tree[key].get('object', '') == 'triplex_node':
                # Get existing variables.
                name = tree[key].get('name', '')
                power = tree[key].get('power_12', '')
                parent = tree[key].get('parent', '')
                phases = tree[key].get('phases', '')
                # Replace object and reintroduce variables.
                tree[key] = copy(blankZipModel)
                tree[key]['name'] = name
                tree[key]['base_power_12'] = powerClean(power)
                tree[key]['parent'] = parent
                tree[key]['phases'] = phases
        # Function to determine how low we can tap down in the CVR case:

        def loweringPotential(baseLine):
            ''' Given a baseline end of line voltage, how many more percent can we shave off the substation voltage? '''
            ''' testsWePass = [122.0,118.0,200.0,110.0] '''
            lower = int(math.floor((baseLine / 114.0 - 1) * 100)) - 1
            # If lower is negative, we can't return it because we'd be
            # undervolting beyond what baseline already was!
            if lower < 0:
                return baselineTap
            else:
                return baselineTap - lower
        # Run all the powerflows.
        powerflows = []
        for doingCvr in [False, True]:
            # For each load level in the tenLoadLevels, run a powerflow with
            # the load objects scaled to the level.
            for desiredLoad in tenLoadLevels:
                # Find the total load that was defined in Milsoft:
                loadList = []
                for key in tree:
                    if tree[key].get('object', '') == 'triplex_load':
                        loadList.append(tree[key].get('base_power_12', ''))
                totalLoad = sum([float(x) for x in loadList])
                # Rescale each triplex load:
                for key in tree:
                    if tree[key].get('object', '') == 'triplex_load':
                        currentPow = float(tree[key]['base_power_12'])
                        ratio = desiredLoad / totalLoad
                        tree[key]['base_power_12'] = str(currentPow * ratio)
                # If we're doing CVR then lower the voltage.
                if doingCvr:
                    # Find the minimum voltage we can tap down to:
                    newTapPos = baselineTap
                    for row in powerflows:
                        if row.get('loadLevel', '') == desiredLoad:
                            newTapPos = loweringPotential(
                                row.get('lowVoltage', 114))
                    # Tap it down to there.
                    # MAYBEFIX: do each phase separately because that's how
                    # it's done in the field... Oof.
                    tree[regConfIndex]['tap_pos_A'] = str(newTapPos)
                    tree[regConfIndex]['tap_pos_B'] = str(newTapPos)
                    tree[regConfIndex]['tap_pos_C'] = str(newTapPos)
                # Run the model through gridlab and put outputs in the table.
                output = gridlabd.runInFilesystem(tree, attachments=attachments,
                                                  keepFiles=True, workDir=modelDir)
                os.remove(pJoin(modelDir, "PID.txt"))
                p = output['Zregulator.csv']['power_in.real'][0]
                q = output['Zregulator.csv']['power_in.imag'][0]
                s = math.sqrt(p**2 + q**2)
                lossTotal = 0.0
                for device in ['ZlossesOverhead.csv', 'ZlossesTransformer.csv', 'ZlossesUnderground.csv']:
                    for letter in ['A', 'B', 'C']:
                        r = output[device][
                            'sum(power_losses_' + letter + '.real)'][0]
                        i = output[device][
                            'sum(power_losses_' + letter + '.imag)'][0]
                        lossTotal += math.sqrt(r**2 + i**2)
                # Entire output:
                powerflows.append({
                    'doingCvr': doingCvr,
                    'loadLevel': desiredLoad,
                    'realPower': p,
                    'powerFactor': p / s,
                    'losses': lossTotal,
                    'subVoltage': (
                        output['ZsubstationBottom.csv']['voltage_A'][0] +
                        output['ZsubstationBottom.csv']['voltage_B'][0] +
                        output['ZsubstationBottom.csv']['voltage_C'][0]) / 3 / 60,
                    'lowVoltage': output['ZvoltageJiggle.csv']['min(voltage_12.mag)'][0] / 2,
                    'highVoltage': output['ZvoltageJiggle.csv']['max(voltage_12.mag)'][0] / 2})
        # For a given load level, find two points to interpolate on.

        def getInterpPoints(t):
            ''' Find the two points we can interpolate from. '''
            ''' tests pass on [tenLoadLevels[0],tenLoadLevels[5]+499,tenLoadLevels[-1]-988] '''
            loc = sorted(tenLoadLevels + [t]).index(t)
            if loc == 0:
                return (tenLoadLevels[0], tenLoadLevels[1])
            elif loc > len(tenLoadLevels) - 2:
                return (tenLoadLevels[-2], tenLoadLevels[-1])
            else:
                return (tenLoadLevels[loc - 1], tenLoadLevels[loc + 1])
        # Calculate peak reduction.
        for row in monthData:
            peak = row['histPeak']
            peakPoints = getInterpPoints(peak)
            peakTopBase = [x for x in powerflows if x.get(
                'loadLevel', '') == peakPoints[-1] and x.get('doingCvr', '') == False][0]
            peakTopCvr = [x for x in powerflows if x.get(
                'loadLevel', '') == peakPoints[-1] and x.get('doingCvr', '') == True][0]
            peakBottomBase = [x for x in powerflows if x.get(
                'loadLevel', '') == peakPoints[0] and x.get('doingCvr', '') == False][0]
            peakBottomCvr = [x for x in powerflows if x.get(
                'loadLevel', '') == peakPoints[0] and x.get('doingCvr', '') == True][0]
            # Linear interpolation so we aren't running umpteen million
            # loadflows.
            x = (peakPoints[0], peakPoints[1])
            y = (peakTopBase['realPower'] - peakTopCvr['realPower'],
                 peakBottomBase['realPower'] - peakBottomCvr['realPower'])
            peakRed = y[0] + (y[1] - y[0]) * (peak - x[0]) / (x[1] - x[0])
            row['peakReduction'] = peakRed
        # Calculate energy reduction and loss reduction based on average load.
        for row in monthData:
            avgEnergy = row['histAverage']
            energyPoints = getInterpPoints(avgEnergy)
            avgTopBase = [x for x in powerflows if x.get(
                'loadLevel', '') == energyPoints[-1] and x.get('doingCvr', '') == False][0]
            avgTopCvr = [x for x in powerflows if x.get(
                'loadLevel', '') == energyPoints[-1] and x.get('doingCvr', '') == True][0]
            avgBottomBase = [x for x in powerflows if x.get(
                'loadLevel', '') == energyPoints[0] and x.get('doingCvr', '') == False][0]
            avgBottomCvr = [x for x in powerflows if x.get(
                'loadLevel', '') == energyPoints[0] and x.get('doingCvr', '') == True][0]
            # Linear interpolation so we aren't running umpteen million
            # loadflows.
            x = (energyPoints[0], energyPoints[1])
            y = (avgTopBase['realPower'] - avgTopCvr['realPower'],
                 avgBottomBase['realPower'] - avgBottomCvr['realPower'])
            energyRed = y[0] + \
                (y[1] - y[0]) * (avgEnergy - x[0]) / (x[1] - x[0])
            row['energyReduction'] = energyRed
            lossY = (avgTopBase['losses'] - avgTopCvr['losses'],
                     avgBottomBase['losses'] - avgBottomCvr['losses'])
            lossRed = lossY[0] + (lossY[1] - lossY[0]) * \
                (avgEnergy - x[0]) / (x[1] - x[0])
            row['lossReduction'] = lossRed
        # Multiply by dollars.
        for row in monthData:
            row['energyReductionDollars'] = row['energyReduction'] / 1000 * \
                (rates['wholesaleEnergyCostPerKwh'] -
                 rates['retailEnergyCostPerKwh'])
            row['peakReductionDollars'] = row['peakReduction'] / \
                1000 * rates['peakDemandCost' + row['season'] + 'PerKw']
            row['lossReductionDollars'] = row['lossReduction'] / \
                1000 * rates['wholesaleEnergyCostPerKwh']
        # Pretty output

        def plotTable(inData):
            fig = plt.figure(figsize=(10, 5))
            plt.axis('off')
            plt.tight_layout()
            plt.table(cellText=[row for row in inData[1:]],
                      loc='center',
                      rowLabels=range(len(inData) - 1),
                      colLabels=inData[0])

        def dictalToMatrix(dictList):
            ''' Take our dictal format to a matrix. '''
            matrix = [dictList[0].keys()]
            for row in dictList:
                matrix.append(row.values())
            return matrix
        # Powerflow results.
        plotTable(dictalToMatrix(powerflows))
        Plot.save_fig(plt, pJoin(modelDir, "powerflowTable.png"))
        # Monetary results.
        # To print partial money table
        monthDataMat = dictalToMatrix(monthData)
        dimX = len(monthDataMat)
        dimY = len(monthDataMat[0])
        monthDataPart = []
        for k in range(0, dimX):
            monthDatatemp = []
            for m in range(4, dimY):
                monthDatatemp.append(monthDataMat[k][m])
            monthDataPart.append(monthDatatemp)

        plotTable(monthDataPart)
        Plot.save_fig(plt, pJoin(modelDir, "moneyTable.png"))
        allOutput["monthDataMat"] = dictalToMatrix(monthData)
        allOutput["monthDataPart"] = monthDataPart
        # Graph the money data.
        fig = plt.figure(figsize=(10, 8))
        indices = [r['monthName'] for r in monthData]
        d1 = [r['energyReductionDollars'] for r in monthData]
        d2 = [r['lossReductionDollars'] for r in monthData]
        d3 = [r['peakReductionDollars'] for r in monthData]
        ticks = range(len(d1))
        bar_erd = plt.bar(ticks, d1, color='red')
        bar_lrd = plt.bar(ticks, d2, color='green')
        bar_prd = plt.bar(ticks, d3, color='blue', yerr=d2)
        plt.legend([bar_prd[0], bar_lrd[0], bar_erd[0]], ['peakReductionDollars', 'lossReductionDollars', 'energyReductionDollars'], bbox_to_anchor=(0., 1.015, 1., .102), loc=3,
                   ncol=2, mode="expand", borderaxespad=0.1)
        plt.xticks([t + 0.5 for t in ticks], indices)
        plt.ylabel('Utility Savings ($)')
        plt.tight_layout(5.5, 1.3, 1.2)
        fig.autofmt_xdate()
        Plot.save_fig(plt, pJoin(modelDir, "spendChart.png"))
        allOutput["energyReductionDollars"] = d1
        allOutput["lossReductionDollars"] = d2
        allOutput["peakReductionDollars"] = d3
        # Graph the cumulative savings.
        fig = plt.figure(figsize=(10, 5))
        annualSavings = sum(d1) + sum(d2) + sum(d3)
        annualSave = lambda x: (
            annualSavings - rates['omCost']) * x - rates['capitalCost']
        simplePayback = rates['capitalCost'] / \
            (annualSavings - rates['omCost'])
        plt.xlabel('Year After Installation')
        plt.xlim(0, 30)
        plt.ylabel('Cumulative Savings ($)')
        plt.plot([0 for x in range(31)], c='gray')
        plt.axvline(x=simplePayback, ymin=0, ymax=1, c='gray', linestyle='--')
        plt.plot([annualSave(x) for x in range(31)], c='green')
        Plot.save_fig(plt, pJoin(modelDir, "savingsChart.png"))
        allOutput["annualSave"] = [annualSave(x) for x in range(31)]
        # Update the runTime in the input file.
        endTime = datetime.datetime.now()
        inputDict["runTime"] = str(
            datetime.timedelta(seconds=int((endTime - startTime).total_seconds())))
        fs.save(pJoin(modelDir, "allInputData.json"), json.dumps(inputDict, indent=4))
        # Write output file.
        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!!!"
        print e
        cancel(modelDir)
Ejemplo n.º 3
0
                + "<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 omf.web.send_link(email, message, user)
        except Exception, e:
            logger.exception("ERROR: failed to send model completed running email to user %s. Exception", email)
            print "ERROR: failed to send model failed running email to user", email, "with exception", e
        cancel(modelDir)


def avg(inList):
    """ Average a list. Really wish this was built-in. """
    return sum(inList) / len(inList)


def hdmAgg(series, func, level, stamps):
    """ Simple hour/day/month aggregation for Gridlab. """
    if level in ["days", "months"]:
        return aggSeries(stamps, series, func, level)
    else:
        return series

Ejemplo n.º 4
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