Exemple #1
0
def run(modelDir, inputDict):
    ''' Run the model in its directory. '''
    # Check whether model exist or not
    if not os.path.isdir(modelDir):
        os.makedirs(modelDir)
        inputDict["created"] = str(dt.datetime.now())
    # MAYBEFIX: remove this data dump. Check showModel in web.py and renderTemplate()
    with open(pJoin(modelDir, "allInputData.json"), "w") as inputFile:
        json.dump(inputDict, inputFile, indent=4)
    # Copy spcific climate data into model directory
    shutil.copy(
        pJoin(__metaModel__._omfDir, "data", "Climate",
              inputDict["climateName"] + ".tmy2"),
        pJoin(modelDir, "climate.tmy2"))
    # Ready to run
    startTime = dt.datetime.now()
    # Set up SAM data structures.
    ssc = nrelsam.SSCAPI()
    dat = ssc.ssc_data_create()
    # Required user inputs.
    ssc.ssc_data_set_string(dat, "file_name", modelDir + "/climate.tmy2")
    ssc.ssc_data_set_number(dat, "system_size",
                            float(inputDict.get("systemSize", 100)))
    ssc.ssc_data_set_number(dat, "derate", float(inputDict.get("derate",
                                                               0.77)))
    ssc.ssc_data_set_number(dat, "track_mode",
                            float(inputDict.get("trackingMode", 0)))
    ssc.ssc_data_set_number(dat, "azimuth",
                            float(inputDict.get("azimuth", 180)))
    # Advanced inputs with defaults.
    ssc.ssc_data_set_number(dat, "rotlim", float(inputDict.get("rotlim", 45)))
    ssc.ssc_data_set_number(dat, "t_noct", float(inputDict.get("t_noct", 45)))
    ssc.ssc_data_set_number(dat, "t_ref", float(inputDict.get("t_ref", 25)))
    ssc.ssc_data_set_number(dat, "gamma", float(inputDict.get("gamma", 0.5)))
    ssc.ssc_data_set_number(dat, "inv_eff",
                            float(inputDict.get("inv_eff", 0.92)))
    ssc.ssc_data_set_number(dat, "fd", float(inputDict.get("fd", 1)))
    ssc.ssc_data_set_number(dat, "i_ref", float(inputDict.get("i_ref", 1000)))
    ssc.ssc_data_set_number(dat, "poa_cutin",
                            float(inputDict.get("poa_cutin", 0)))
    ssc.ssc_data_set_number(dat, "w_stow", float(inputDict.get("w_stow", 0)))
    # Complicated optional inputs.
    ssc.ssc_data_set_number(dat, "tilt_eq_lat", 1)
    # ssc.ssc_data_set_array(dat, 'shading_hourly', ...) 	# Hourly beam shading factors
    # ssc.ssc_data_set_matrix(dat, 'shading_mxh', ...) 		# Month x Hour beam shading factors
    # ssc.ssc_data_set_matrix(dat, ' shading_azal', ...) 	# Azimuth x altitude beam shading factors
    # ssc.ssc_data_set_number(dat, 'shading_diff', ...) 	# Diffuse shading factor
    # ssc.ssc_data_set_number(dat, 'enable_user_poa', ...)	# Enable user-defined POA irradiance input = 0 or 1
    # ssc.ssc_data_set_array(dat, 'user_poa', ...) 			# User-defined POA irradiance in W/m2
    # ssc.ssc_data_set_number(dat, 'tilt', 999)
    # Run PV system simulation.
    mod = ssc.ssc_module_create("pvwattsv1")
    ssc.ssc_module_exec(mod, dat)
    # Setting options for start time.
    simLengthUnits = inputDict.get("simLengthUnits", "hours")
    simStartDate = inputDict.get("simStartDate", "2014-01-01")
    # Set the timezone to be UTC, it won't affect calculation and display, relative offset handled in pvWatts.html
    startDateTime = simStartDate + " 00:00:00 UTC"
    # Set aggregation function constants.
    agg = lambda x, y: _aggData(
        x, y, inputDict["simStartDate"], int(inputDict["simLength"]),
        inputDict.get("simLengthUnits", "hours"), ssc, dat)
    avg = lambda x: sum(x) / len(x)
    # Timestamp output.
    outData = {}
    outData["timeStamps"] = [
        dt.datetime.strftime(
            dt.datetime.strptime(startDateTime[0:19], "%Y-%m-%d %H:%M:%S") +
            dt.timedelta(**{simLengthUnits: x}), "%Y-%m-%d %H:%M:%S") + " UTC"
        for x in range(int(inputDict.get("simLength", 8760)))
    ]
    # Geodata output.
    outData["city"] = ssc.ssc_data_get_string(dat, "city")
    outData["state"] = ssc.ssc_data_get_string(dat, "state")
    outData["lat"] = ssc.ssc_data_get_number(dat, "lat")
    outData["lon"] = ssc.ssc_data_get_number(dat, "lon")
    outData["elev"] = ssc.ssc_data_get_number(dat, "elev")
    # Weather output.
    outData["climate"] = {}
    outData["climate"]["Direct Irradiance (W/m^2)"] = agg("dn", avg)
    outData["climate"]["Difuse Irradiance (W/m^2)"] = agg("df", avg)
    outData["climate"]["Ambient Temperature (F)"] = agg("tamb", avg)
    outData["climate"]["Cell Temperature (F)"] = agg("tcell", avg)
    outData["climate"]["Wind Speed (m/s)"] = agg("wspd", avg)
    # Power generation.
    outData["powerOutputAc"] = [x for x in agg("ac", avg)]
    # Cashflow outputs.
    lifeSpan = int(inputDict.get("lifeSpan", 30))
    lifeYears = range(1, 1 + lifeSpan)
    retailCost = float(inputDict.get("retailCost", 0.0))
    degradation = float(inputDict.get("degradation", 0.5)) / 100
    installCost = float(inputDict.get("installCost", 0.0))
    outData["oneYearGenerationWh"] = sum(outData["powerOutputAc"])
    outData["lifeGenerationDollars"] = [
        roundSig(
            retailCost * (1.0 / 1000.0) * outData["oneYearGenerationWh"] *
            (1.0 - (x * degradation)), 2) for x in lifeYears
    ]
    outData["lifeOmCosts"] = [
        -1.0 * float(inputDict["omCost"]) for x in lifeYears
    ]
    outData["lifePurchaseCosts"] = [-1.0 * installCost
                                    ] + [0 for x in lifeYears[1:]]
    outData["netCashFlow"] = [
        roundSig(x + y + z, 2)
        for (x, y,
             z) in zip(outData["lifeGenerationDollars"],
                       outData["lifeOmCosts"], outData["lifePurchaseCosts"])
    ]
    outData["cumCashFlow"] = map(lambda x: roundSig(x, 2),
                                 _runningSum(outData["netCashFlow"]))
    outData["ROI"] = roundSig(sum(outData["netCashFlow"]), 2)
    #TODO: implement these two.
    outData["NPV"] = "TBD"
    outData["IRR"] = "TBD"
    # Monthly aggregation outputs.
    months = {
        "Jan": 0,
        "Feb": 1,
        "Mar": 2,
        "Apr": 3,
        "May": 4,
        "Jun": 5,
        "Jul": 6,
        "Aug": 7,
        "Sep": 8,
        "Oct": 9,
        "Nov": 10,
        "Dec": 11
    }
    totMonNum = lambda x: sum([
        z for (y, z) in zip(outData["timeStamps"], outData["powerOutputAc"])
        if y.startswith(simStartDate[0:4] + "-{0:02d}".format(x + 1))
    ])
    outData["monthlyGeneration"] = [[a, roundSig(
        totMonNum(b),
        2)] for (a, b) in sorted(months.items(), key=lambda x: x[1])]
    # Heatmaped hour+month outputs.
    hours = range(24)
    from random import random
    totHourMon = lambda h, m: sum([
        z for (y, z) in zip(outData["timeStamps"], outData["powerOutputAc"])
        if y[5:7] == "{0:02d}".format(m + 1) and y[11:13] == "{0:02d}".format(
            h + 1)
    ])
    outData["seasonalPerformance"] = [[x, y, totHourMon(x, y)] for x in hours
                                      for y in months.values()]
    # Stdout/stderr.
    outData["stdout"] = "Success"
    outData["stderr"] = ""
    # Write the output.
    with open(pJoin(modelDir, "allOutputData.json"), "w") as outFile:
        json.dump(outData, outFile, indent=4)
    # Update the runTime in the input file.
    endTime = dt.datetime.now()
    inputDict["runTime"] = str(
        dt.timedelta(seconds=int((endTime - startTime).total_seconds())))
    with open(pJoin(modelDir, "allInputData.json"), "w") as inFile:
        json.dump(inputDict, inFile, indent=4)
Exemple #2
0
def run(modelDir, inputDict):
	''' Run the model in its directory. '''
	# Check whether model exist or not
	if not os.path.isdir(modelDir):
		os.makedirs(modelDir)
		inputDict["created"] = str(datetime.datetime.now())
	# MAYBEFIX: remove this data dump. Check showModel in web.py and renderTemplate()
	with open(pJoin(modelDir, "allInputData.json"),"w") as inputFile:
		json.dump(inputDict, inputFile, indent = 4)
	# Copy spcific climate data into model directory
	shutil.copy(pJoin(__metaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"), 
		pJoin(modelDir, "climate.tmy2"))
	# Ready to run
	startTime = datetime.datetime.now()
	# Set up SAM data structures.
	ssc = nrelsam.SSCAPI()
	dat = ssc.ssc_data_create()
	# Required user inputs.
	ssc.ssc_data_set_string(dat, "file_name", modelDir + "/climate.tmy2")
	ssc.ssc_data_set_number(dat, "system_size", float(inputDict["systemSize"]))
	ssc.ssc_data_set_number(dat, "derate", float(inputDict["derate"]))
	ssc.ssc_data_set_number(dat, "track_mode", float(inputDict["trackingMode"]))
	ssc.ssc_data_set_number(dat, "azimuth", float(inputDict["azimuth"]))
	# Advanced inputs with defaults.
	ssc.ssc_data_set_number(dat, "rotlim", float(inputDict["rotlim"]))
	ssc.ssc_data_set_number(dat, "t_noct", float(inputDict["t_noct"]))
	ssc.ssc_data_set_number(dat, "t_ref", float(inputDict["t_ref"]))
	ssc.ssc_data_set_number(dat, "gamma", float(inputDict["gamma"]))
	ssc.ssc_data_set_number(dat, "inv_eff", float(inputDict["inv_eff"]))
	ssc.ssc_data_set_number(dat, "fd", float(inputDict["fd"]))
	ssc.ssc_data_set_number(dat, "i_ref", float(inputDict["i_ref"]))
	ssc.ssc_data_set_number(dat, "poa_cutin", float(inputDict["poa_cutin"]))
	ssc.ssc_data_set_number(dat, "w_stow", float(inputDict["w_stow"]))
	# Complicated optional inputs.
	ssc.ssc_data_set_number(dat, "tilt_eq_lat", 1)
	# ssc.ssc_data_set_array(dat, 'shading_hourly', ...) 	# Hourly beam shading factors
	# ssc.ssc_data_set_matrix(dat, 'shading_mxh', ...) 		# Month x Hour beam shading factors
	# ssc.ssc_data_set_matrix(dat, 'shading_azal', ...) 	# Azimuth x altitude beam shading factors
	# ssc.ssc_data_set_number(dat, 'shading_diff', ...) 	# Diffuse shading factor
	# ssc.ssc_data_set_number(dat, 'enable_user_poa', ...)	# Enable user-defined POA irradiance input = 0 or 1
	# ssc.ssc_data_set_array(dat, 'user_poa', ...) 			# User-defined POA irradiance in W/m2
	# ssc.ssc_data_set_number(dat, 'tilt', 999)
	# Run PV system simulation.
	mod = ssc.ssc_module_create("pvwattsv1")
	ssc.ssc_module_exec(mod, dat)
	# Setting options for start time.
	simLengthUnits = inputDict.get("simLengthUnits","")
	simStartDate = inputDict["simStartDate"]
	# Set the timezone to be UTC, it won't affect calculation and display, relative offset handled in pvWatts.html 
	startDateTime = simStartDate + " 00:00:00 UTC"
	# Set aggregation function constants.
	agg = lambda x,y:_aggData(x,y,inputDict["simStartDate"],
		int(inputDict["simLength"]), inputDict["simLengthUnits"], ssc, dat)
	avg = lambda x:sum(x)/len(x)
	# Timestamp output.
	outData = {}
	outData["timeStamps"] = [datetime.datetime.strftime(
		datetime.datetime.strptime(startDateTime[0:19],"%Y-%m-%d %H:%M:%S") + 
		datetime.timedelta(**{simLengthUnits:x}),"%Y-%m-%d %H:%M:%S") + " UTC" for x in range(int(inputDict["simLength"]))]
	# Geodata output.
	outData["city"] = ssc.ssc_data_get_string(dat, "city")
	outData["state"] = ssc.ssc_data_get_string(dat, "state")
	outData["lat"] = ssc.ssc_data_get_number(dat, "lat")
	outData["lon"] = ssc.ssc_data_get_number(dat, "lon")
	outData["elev"] = ssc.ssc_data_get_number(dat, "elev")
	# Weather output.
	outData["climate"] = {}
	outData["climate"]["Direct Irradiance (W/m^2)"] = agg("dn", avg)
	outData["climate"]["Difuse Irradiance (W/m^2)"] = agg("df", avg)
	outData["climate"]["Ambient Temperature (F)"] = agg("tamb", avg)
	outData["climate"]["Cell Temperature (F)"] = agg("tcell", avg)
	outData["climate"]["Wind Speed (m/s)"] = agg("wspd", avg)
	# Power generation.
	outData["Consumption"] = {}
	outData["Consumption"]["Power"] = [x for x in agg("ac", avg)]
	outData["Consumption"]["Losses"] = [0 for x in agg("ac", avg)]
	outData["Consumption"]["DG"] = agg("ac", avg)
	# Stdout/stderr.
	outData["stdout"] = "Success"
	outData["stderr"] = ""
	# Write the output.
	with open(pJoin(modelDir,"allOutputData.json"),"w") as outFile:
		json.dump(outData, outFile, indent=4)
	# Update the runTime in the input file.
	endTime = 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)
Exemple #3
0
		pass
	try:
		# Check whether model exist or not
		if not os.path.isdir(modelDir):
			os.makedirs(modelDir)
			inputDict["created"] = str(dt.datetime.now())
		# MAYBEFIX: remove this data dump. Check showModel in web.py and renderTemplate()
		with open(pJoin(modelDir, "allInputData.json"),"w") as inputFile:
			json.dump(inputDict, inputFile, indent = 4)
		# Copy spcific climate data into model directory
		shutil.copy(pJoin(__metaModel__._omfDir, "data", "Climate", inputDict["climateName"] + ".tmy2"), 
			pJoin(modelDir, "climate.tmy2"))
		# Ready to run
		startTime = dt.datetime.now()
		# Set up SAM data structures.
		ssc = nrelsam.SSCAPI()
		dat = ssc.ssc_data_create()
		# Required user inputs.
		ssc.ssc_data_set_string(dat, "file_name", modelDir + "/climate.tmy2")
		ssc.ssc_data_set_number(dat, "system_size", float(inputDict.get("systemSize", 100)))
		derate = float(inputDict.get("pvModuleDerate", 99.5))/100 \
			* float(inputDict.get("mismatch", 99.5))/100 \
			* float(inputDict.get("diodes", 99.5))/100 \
			* float(inputDict.get("dcWiring", 99.5))/100 \
			* float(inputDict.get("acWiring", 99.5))/100 \
			* float(inputDict.get("soiling", 99.5))/100 \
			* float(inputDict.get("shading", 99.5))/100 \
			* float(inputDict.get("sysAvail", 99.5))/100 \
			* float(inputDict.get("age", 99.5))/100 \
			* float(inputDict.get("inverterEfficiency", 92))/100
		ssc.ssc_data_set_number(dat, "derate", derate)
Exemple #4
0
def run(modelDir, inputDict):
    try:
        ''' Run the model in its directory. '''
        # Check whether model exist or not
        if not os.path.isdir(modelDir):
            os.makedirs(modelDir)
            inputDict["created"] = str(dt.datetime.now())
        # MAYBEFIX: remove this data dump. Check showModel in web.py and renderTemplate()
        with open(pJoin(modelDir, "allInputData.json"), "w") as inputFile:
            json.dump(inputDict, inputFile, indent=4)
        # Copy spcific climate data into model directory
        shutil.copy(
            pJoin(__metaModel__._omfDir, "data", "Climate",
                  inputDict["climateName"] + ".tmy2"),
            pJoin(modelDir, "climate.tmy2"))
        # Ready to run
        startTime = dt.datetime.now()
        # Set up SAM data structures.
        ssc = nrelsam.SSCAPI()
        dat = ssc.ssc_data_create()
        # Required user inputs.
        ssc.ssc_data_set_string(dat, "file_name", modelDir + "/climate.tmy2")
        # TODO: FIX THIS!!!! IT SHOULD BE AVGSYS*PEN*RESCUSTOMERS
        ssc.ssc_data_set_number(dat, "system_size",
                                float(inputDict["avgSystemSize"]))
        # SAM options where we take defaults.
        ssc.ssc_data_set_number(dat, "derate", 0.97)
        ssc.ssc_data_set_number(dat, "track_mode", 0)
        ssc.ssc_data_set_number(dat, "azimuth", 180)
        ssc.ssc_data_set_number(dat, "tilt_eq_lat", 1)
        # Run PV system simulation.
        mod = ssc.ssc_module_create("pvwattsv1")
        ssc.ssc_module_exec(mod, dat)
        # Set the timezone to be UTC, it won't affect calculation and display, relative offset handled in pvWatts.html
        startDateTime = "2013-01-01 00:00:00 UTC"
        # Timestamp output.
        outData = {}
        outData["timeStamps"] = [
            dt.datetime.strftime(
                dt.datetime.strptime(startDateTime[0:19], "%Y-%m-%d %H:%M:%S")
                + dt.timedelta(**{"hours": x}), "%Y-%m-%d %H:%M:%S") + " UTC"
            for x in range(int(8760))
        ]
        # Geodata output.
        outData["city"] = ssc.ssc_data_get_string(dat, "city")
        outData["state"] = ssc.ssc_data_get_string(dat, "state")
        outData["lat"] = ssc.ssc_data_get_number(dat, "lat")
        outData["lon"] = ssc.ssc_data_get_number(dat, "lon")
        outData["elev"] = ssc.ssc_data_get_number(dat, "elev")
        # Weather output.
        outData["climate"] = {}
        outData["climate"][
            "Global Horizontal Radiation (W/m^2)"] = ssc.ssc_data_get_array(
                dat, "gh")
        outData["climate"][
            "Plane of Array Irradiance (W/m^2)"] = ssc.ssc_data_get_array(
                dat, "poa")
        outData["climate"]["Ambient Temperature (F)"] = ssc.ssc_data_get_array(
            dat, "tamb")
        outData["climate"]["Cell Temperature (F)"] = ssc.ssc_data_get_array(
            dat, "tcell")
        outData["climate"]["Wind Speed (m/s)"] = ssc.ssc_data_get_array(
            dat, "wspd")
        # Power generation.
        outData["powerOutputAc"] = ssc.ssc_data_get_array(dat, "ac")
        # Monthly aggregation outputs.
        months = {
            "Jan": 0,
            "Feb": 1,
            "Mar": 2,
            "Apr": 3,
            "May": 4,
            "Jun": 5,
            "Jul": 6,
            "Aug": 7,
            "Sep": 8,
            "Oct": 9,
            "Nov": 10,
            "Dec": 11
        }
        totMonNum = lambda x: sum([
            z
            for (y, z) in zip(outData["timeStamps"], outData["powerOutputAc"])
            if y.startswith(startDateTime[0:4] + "-{0:02d}".format(x + 1))
        ])
        outData["monthlyGeneration"] = [[a, roundSig(
            totMonNum(b),
            2)] for (a, b) in sorted(months.items(), key=lambda x: x[1])]
        monthlyNoConsumerServedSales = []
        monthlyKWhSold = []
        monthlyRevenue = []
        totalKWhSold = []
        totalRevenue = []
        for key in inputDict:
            # MAYBEFIX: data in list may not be ordered by month.
            if key.endswith("Sale"):
                monthlyNoConsumerServedSales.append(
                    [key[:3].title(),
                     float(inputDict.get(key, 0))])
            elif key.endswith("KWh"):  # the order of calculation matters
                monthlyKWhSold.append(
                    [key[:3].title(),
                     float(inputDict.get(key, 0))])
            elif key.endswith("Rev"):
                monthlyRevenue.append(
                    [key[:3].title(),
                     float(inputDict.get(key, 0))])
            elif key.endswith("KWhT"):
                totalKWhSold.append(
                    [key[:3].title(),
                     float(inputDict.get(key, 0))])
            elif key.endswith("RevT"):
                totalRevenue.append(
                    [key[:3].title(),
                     float(inputDict.get(key, 0))])
        outData["monthlyNoConsumerServedSales"] = sorted(
            monthlyNoConsumerServedSales, key=lambda x: months[x[0]])
        outData["monthlyKWhSold"] = sorted(monthlyKWhSold,
                                           key=lambda x: months[x[0]])
        outData["monthlyRevenue"] = sorted(monthlyRevenue,
                                           key=lambda x: months[x[0]])
        outData["totalKWhSold"] = sorted(totalKWhSold,
                                         key=lambda x: months[x[0]])
        outData["totalRevenue"] = sorted(totalRevenue,
                                         key=lambda x: months[x[0]])
        outData["totalGeneration"] = [[
            sorted(months.items(), key=lambda x: x[1])[i][0],
            outData["monthlyGeneration"][i][1] *
            outData["monthlyNoConsumerServedSales"][i][1] *
            (float(inputDict.get("resPenetration", 5)) / 100 / 1000)
        ] for i in range(12)]
        outData["totalSolarSold"] = [[
            sorted(months.items(), key=lambda x: x[1])[i][0],
            outData["totalKWhSold"][i][1] - outData["totalGeneration"][i][1]
        ] for i in range(12)]
        ##################
        # TODO: add retailCost to the calculation.
        ##################
        ## Flow Diagram Calculations, and order of calculation matters
        # BAU case
        outData["BAU"] = {}
        # E23 = E11
        outData["BAU"]["totalKWhPurchased"] = float(
            inputDict.get("totalKWhPurchased", 1))
        # E24 = SUM(E19:P19)
        outData["BAU"]["totalKWhSales"] = sum([x[1] for x in totalKWhSold])
        # E25 = E23-E24
        outData["BAU"]["losses"] = float(inputDict.get(
            "totalKWhPurchased", 0)) - sum(
                [totalKWhSold[i][1] for i in range(12)])
        # E26 = E25/E23
        outData["BAU"]["effectiveLossRate"] = outData["BAU"][
            "losses"] / outData["BAU"]["totalKWhPurchased"]
        # E27 = 0
        outData["BAU"]["annualSolarGen"] = 0
        # E28 = SUM(E17:P17)
        outData["BAU"]["resNonSolarKWhSold"] = sum(
            [monthlyKWhSold[i][1] for i in range(12)])
        # E29 = 0
        outData["BAU"]["solarResDemand"] = 0
        # E30 = 0
        outData["BAU"]["solarResSold"] = 0
        # E31 = E24-E28
        outData["BAU"]["nonResKWhSold"] = outData["BAU"][
            "totalKWhSales"] - outData["BAU"]["resNonSolarKWhSold"]
        # E32 = 0
        outData["BAU"]["costSolarGen"] = 0
        # E33 = SUM(E20:P20)-SUM(E18:P18)+E10
        outData["BAU"]["nonResRev"] = sum([
            totalRevenue[i][1] for i in range(12)
        ]) - sum([monthlyRevenue[i][1] for i in range(12)]) + float(
            inputDict.get("otherElecRevenue"))
        # E34 = (SUM(E18:P18)-SUM(E16:P16)*E6)/SUM(E17:P17)
        outData["BAU"]["effectiveResRate"] = (
            sum([monthlyRevenue[i][1] for i in range(12)]) -
            sum([monthlyNoConsumerServedSales[i][1] for i in range(12)]) *
            float(inputDict.get("customServiceCharge", 0))) / sum(
                [monthlyKWhSold[i][1] for i in range(12)])
        # E35 = E34*E28+SUM(E16:P16)*E6
        outData["BAU"]["resNonSolarRev"] = outData["BAU"][
            "effectiveResRate"] * outData["BAU"]["resNonSolarKWhSold"] + sum([
                monthlyNoConsumerServedSales[i][1] for i in range(12)
            ]) * float(inputDict.get("customServiceCharge", 0))
        # E36 = E30*E34
        outData["BAU"]["solarResRev"] = 0
        # E37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71), update after Form 7 model
        outData["BAU"]["nonPowerCosts"] = 0
        # E38 = E23-E25-E28-E30-E31
        outData["BAU"]["energyAllBal"] = 0
        # E39 = E36+E33+E35-E47-E72-E37
        outData["BAU"]["dollarAllBal"] = 0
        # E40 = 0
        outData["BAU"]["avgMonthlyBillSolarCus"] = 0
        # E41 = E35/SUM(E16:P16)
        avgCustomerCount = (
            sum([monthlyNoConsumerServedSales[i][1] for i in range(12)]) / 12)
        outData["BAU"]["avgMonthlyBillNonSolarCus"] = outData["BAU"][
            "resNonSolarRev"] / sum(
                [monthlyNoConsumerServedSales[i][1] for i in range(12)])
        # E42 = E63/E24, update after Form 7 model
        outData["BAU"]["costofService"] = 0
        # Solar case
        outData["Solar"] = {}
        # F27 = SUM(E15:P15)
        outData["Solar"]["annualSolarGen"] = sum(
            [outData["totalGeneration"][i][1] for i in range(12)])
        # F24 = E24-F27
        outData["Solar"]["totalKWhSales"] = sum(
            [totalKWhSold[i][1]
             for i in range(12)]) - outData["Solar"]["annualSolarGen"]
        # F23 =F24/(1-E26)
        outData["Solar"]["totalKWhPurchased"] = outData["Solar"][
            "totalKWhSales"] / (1 - outData["BAU"]["effectiveLossRate"])
        outData["totalsolarmonthly"] = [[
            sorted(months.items(),
                   key=lambda x: x[1])[i][0], outData["totalSolarSold"][i][1] /
            (1 - outData["BAU"]["effectiveLossRate"])
        ] for i in range(12)]
        # F25 = F23-F24
        outData["Solar"]["losses"] = (outData["Solar"]["totalKWhPurchased"] -
                                      outData["Solar"]["totalKWhSales"])
        # F26 = E26
        outData["Solar"]["effectiveLossRate"] = outData["BAU"][
            "effectiveLossRate"]
        # F28 = (1-E5)*E28
        outData["Solar"]["resNonSolarKWhSold"] = (
            1 - float(inputDict.get("resPenetration", 0)) /
            100) * outData["BAU"]["resNonSolarKWhSold"]
        # F29 = E5*E28
        outData["Solar"]["solarResDemand"] = float(
            inputDict.get("resPenetration",
                          0)) / 100 * outData["BAU"]["resNonSolarKWhSold"]
        # F30 = F29-F27
        outData["Solar"]["solarResSold"] = outData["Solar"][
            "solarResDemand"] - outData["Solar"]["annualSolarGen"]
        # F31 = E31
        outData["Solar"]["nonResKWhSold"] = outData["BAU"]["nonResKWhSold"]
        # F32 = E9*F27
        outData["Solar"]["costSolarGen"] = float(
            inputDict.get("solarLCoE",
                          0.07)) * outData["Solar"]["annualSolarGen"]
        # F33 = E33
        outData["Solar"]["nonResRev"] = outData["BAU"]["nonResRev"]
        # F34 = E34
        outData["Solar"]["effectiveResRate"] = outData["BAU"][
            "effectiveResRate"]
        # F35 = E35*(1-E5)
        outData["Solar"][
            "resNonSolarRev"] = outData["BAU"]["resNonSolarRev"] * (
                1 - float(inputDict.get("resPenetration", 0.05)) / 100)
        # F30*E34 = Solar revenue from selling at residential rate
        solarSoldRateRev = outData["Solar"]["solarResSold"] * outData["Solar"][
            "effectiveResRate"]
        # (E6+E7)*SUM(E16:P16)*E5 = Solar revenue from charges
        solarChargesRev = (
            float(inputDict.get("customServiceCharge", 0)) +
            float(inputDict.get("solarServiceCharge", 0))) * sum([
                monthlyNoConsumerServedSales[i][1] for i in range(12)
            ]) * float(inputDict.get("resPenetration", 0.05)) / 100
        # F36 = F30*E34+(E6+E7)*SUM(E16:P16)*E5 = solarSoldRate + solarChargesRev
        outData["Solar"]["solarResRev"] = solarSoldRateRev + solarChargesRev
        # F37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71) = E37, update after Form 7 model
        outData["Solar"]["nonPowerCosts"] = 0
        # F38 = F23-F25-F28-F30-E31
        outData["Solar"]["energyAllBal"] = 0
        # F39 = F36+E33+F35-F47-F72-E37
        outData["Solar"]["dollarAllBal"] = 0
        if (float(inputDict.get("resPenetration", 0.05)) > 0):
            # F41 = (F35)/(SUM(E16:P16)*(1-E5))
            outData["Solar"]["avgMonthlyBillNonSolarCus"] = outData["Solar"][
                "resNonSolarRev"] / (sum([
                    monthlyNoConsumerServedSales[i][1] for i in range(12)
                ]) * (1 - float(inputDict.get("resPenetration", 0.05)) / 100))
            # F42 = F30*E34/(SUM(E16:P16)*E5)+E6+E7
            outData["Solar"]["avgMonthlyBillSolarCus"] = outData["Solar"][
                "solarResSold"] * outData["BAU"]["effectiveResRate"] / (sum(
                    [monthlyNoConsumerServedSales[i][1]
                     for i in range(12)]) * float(
                         inputDict.get("resPenetration", 0.05)) / 100) + float(
                             inputDict.get("customServiceCharge", 0)) + float(
                                 inputDict.get("solarServiceCharge", 0))
            # F43 = (F27/(SUM(E16:P16)*E5))*E9
            outData["Solar"]["avgMonthlyBillSolarSolarCus"] = (
                outData["Solar"]["annualSolarGen"] /
                (sum([monthlyNoConsumerServedSales[i][1] for i in range(12)]) *
                 float(inputDict.get("resPenetration", 0.05)) / 100)) * float(
                     inputDict.get("solarLCoE", 0.07))
        else:
            outData["Solar"]["avgMonthlyBillNonSolarCus"] = 0
            outData["Solar"]["avgMonthlyBillSolarCus"] = 0
            outData["Solar"]["avgMonthlyBillSolarSolarCus"] = 0
        # Net Average Monthly Bill
        avgMonthlyBillSolarNet = outData["Solar"][
            "avgMonthlyBillSolarCus"] + outData["Solar"][
                "avgMonthlyBillSolarSolarCus"]
        outData["Solar"]["avgMonthlyBillSolarCus"] = avgMonthlyBillSolarNet
        # F45 = F63/F24, update after Form 7 model
        outData["Solar"]["costofService"] = 0
        ## Form 7 Model
        # E46
        outData["Solar"]["powerProExpense"] = outData["BAU"][
            "powerProExpense"] = float(inputDict.get("powerProExpense", 0))
        # E47 != F47
        outData["BAU"]["costPurchasedPower"] = float(
            inputDict.get("costPurchasedPower", 0))
        # E48
        outData["Solar"]["transExpense"] = outData["BAU"][
            "transExpense"] = float(inputDict.get("transExpense", 0))
        # E49
        outData["Solar"]["distriExpenseO"] = outData["BAU"][
            "distriExpenseO"] = float(inputDict.get("distriExpenseO", 0))
        # E50
        outData["Solar"]["distriExpenseM"] = outData["BAU"][
            "distriExpenseM"] = float(inputDict.get("distriExpenseM", 0))
        # E51
        outData["Solar"]["customerAccountExpense"] = outData["BAU"][
            "customerAccountExpense"] = float(
                inputDict.get("customerAccountExpense", 0))
        # E52
        outData["Solar"]["customerServiceExpense"] = outData["BAU"][
            "customerServiceExpense"] = float(
                inputDict.get("customerServiceExpense", 0))
        # E53
        outData["Solar"]["salesExpense"] = outData["BAU"][
            "salesExpense"] = float(inputDict.get("salesExpense", 0))
        # E54
        outData["Solar"]["adminGeneralExpense"] = outData["BAU"][
            "adminGeneralExpense"] = float(
                inputDict.get("adminGeneralExpense", 0))
        # E56
        outData["Solar"]["depreAmortiExpense"] = outData["BAU"][
            "depreAmortiExpense"] = float(
                inputDict.get("depreAmortiExpense", 0))
        # E57
        outData["Solar"]["taxExpensePG"] = outData["BAU"][
            "taxExpensePG"] = float(inputDict.get("taxExpensePG", 0))
        # E58
        outData["Solar"]["taxExpense"] = outData["BAU"]["taxExpense"] = float(
            inputDict.get("taxExpense", 0))
        # E59
        outData["Solar"]["interestLongTerm"] = outData["BAU"][
            "interestLongTerm"] = float(inputDict.get("interestLongTerm", 0))
        # E60
        outData["Solar"]["interestConstruction"] = outData["BAU"][
            "interestConstruction"] = float(
                inputDict.get("interestConstruction", 0))
        # E61
        outData["Solar"]["interestExpense"] = outData["BAU"][
            "interestExpense"] = float(inputDict.get("interestExpense", 0))
        # E62
        outData["Solar"]["otherDeductions"] = outData["BAU"][
            "otherDeductions"] = float(inputDict.get("otherDeductions", 0))
        # E65
        outData["Solar"]["nonOpMarginInterest"] = outData["BAU"][
            "nonOpMarginInterest"] = float(
                inputDict.get("nonOpMarginInterest", 0))
        # E66
        outData["Solar"]["fundsUsedConstruc"] = outData["BAU"][
            "fundsUsedConstruc"] = float(inputDict.get("fundsUsedConstruc", 0))
        # E67
        outData["Solar"]["incomeEquityInvest"] = outData["BAU"][
            "incomeEquityInvest"] = float(
                inputDict.get("incomeEquityInvest", 0))
        # E68
        outData["Solar"]["nonOpMarginOther"] = outData["BAU"][
            "nonOpMarginOther"] = float(inputDict.get("nonOpMarginOther", 0))
        # E69
        outData["Solar"]["genTransCapCredits"] = outData["BAU"][
            "genTransCapCredits"] = float(
                inputDict.get("genTransCapCredits", 0))
        # E70
        outData["Solar"]["otherCapCreditsPatroDivident"] = outData["BAU"][
            "otherCapCreditsPatroDivident"] = float(
                inputDict.get("otherCapCreditsPatroDivident", 0))
        # E71
        outData["Solar"]["extraItems"] = outData["BAU"]["extraItems"] = float(
            inputDict.get("extraItems", 0))
        # Calculation
        # E45 = SUM(E20:P20)+E10
        outData["BAU"]["operRevPatroCap"] = sum(
            [totalRevenue[i][1]
             for i in range(12)]) + float(inputDict.get("otherElecRevenue", 0))
        # E55 = SUM(E46:E54)
        outData["BAU"]["totalOMExpense"] = float(inputDict.get("powerProExpense")) \
         + float(inputDict.get("costPurchasedPower")) \
         + float(inputDict.get("transExpense")) \
         + float(inputDict.get("distriExpenseO")) \
         + float(inputDict.get("distriExpenseM")) \
         + float(inputDict.get("customerAccountExpense")) \
         + float(inputDict.get("customerServiceExpense")) \
         + float(inputDict.get("salesExpense"))  \
         + float(inputDict.get("adminGeneralExpense"))
        # E63 = SUM(E55:E62)
        outData["BAU"]["totalCostElecService"] = outData["BAU"]["totalOMExpense"] \
         + float(inputDict.get("depreAmortiExpense"))\
         + float(inputDict.get("taxExpensePG"))\
         + float(inputDict.get("taxExpense"))\
         + float(inputDict.get("interestLongTerm"))\
         + float(inputDict.get("interestExpense"))\
         + float(inputDict.get("interestConstruction"))\
         + outData["BAU"]["otherDeductions"]
        # E64 = E45-E63
        outData["BAU"]["patCapOperMargins"] = outData["BAU"][
            "operRevPatroCap"] - outData["BAU"]["totalCostElecService"]
        # E72 = SUM(E64:E71)
        outData["BAU"]["patCapital"] = outData["BAU"]["patCapOperMargins"]\
         + float(inputDict.get("nonOpMarginInterest"))\
         + float(inputDict.get("fundsUsedConstruc"))\
         + float(inputDict.get("incomeEquityInvest"))\
         + float(inputDict.get("nonOpMarginOther"))\
         + float(inputDict.get("genTransCapCredits"))\
         + float(inputDict.get("otherCapCreditsPatroDivident"))\
         + float(inputDict.get("extraItems"))
        # F48 = E48-F27*E34+SUM(E16:P16)*E5*E7
        outData["Solar"]["operRevPatroCap"] = outData["BAU"][
            "operRevPatroCap"] - outData["BAU"]["effectiveResRate"] * outData[
                "Solar"]["annualSolarGen"] + sum(
                    [monthlyNoConsumerServedSales[i][1]
                     for i in range(12)]) * float(
                         inputDict.get("resPenetration", 0.05)) / 100 * float(
                             inputDict.get("solarServiceCharge", 0))
        # F47 = (F23)*E8
        inputDict["costofPower"] = float(inputDict.get(
            "costPurchasedPower", 0)) / float(
                inputDict.get("totalKWhPurchased", 0))
        outData["Solar"]["costPurchasedPower"] = outData["Solar"][
            "totalKWhPurchased"] * float(inputDict.get("costofPower", 0))
        inputDict["costofPower"] = round(inputDict["costofPower"], 3)
        # F55 = SUM(F46:F54)
        outData["Solar"]["totalOMExpense"] = outData["Solar"]["powerProExpense"]\
         + outData["Solar"]["costPurchasedPower"]\
         + outData["Solar"]["transExpense"]\
         + outData["Solar"]["distriExpenseO"]\
         + outData["Solar"]["distriExpenseM"]\
         + outData["Solar"]["customerAccountExpense"]\
         + outData["Solar"]["customerServiceExpense"]\
         + outData["Solar"]["salesExpense"]\
         + outData["Solar"]["adminGeneralExpense"]
        # F63 = E63
        outData["Solar"]["totalCostElecService"] = outData["Solar"]["totalOMExpense"]\
         + outData["Solar"]["depreAmortiExpense"]\
         + outData["Solar"]["taxExpensePG"]\
         + outData["Solar"]["taxExpense"]\
         + outData["Solar"]["interestLongTerm"]\
         + outData["Solar"]["interestConstruction"]\
         + outData["Solar"]["interestExpense"]\
         + outData["Solar"]["otherDeductions"]
        # F64 = F45 - F63
        outData["Solar"]["patCapOperMargins"] = outData["Solar"][
            "operRevPatroCap"] - outData["Solar"]["totalCostElecService"]
        # F72 = SUM(F64:F71)
        outData["Solar"]["patCapital"] = outData["Solar"]["patCapOperMargins"]\
         + outData["Solar"]["nonOpMarginInterest"]\
         + outData["Solar"]["fundsUsedConstruc"]\
         + outData["Solar"]["incomeEquityInvest"]\
         + outData["Solar"]["nonOpMarginOther"]\
         + outData["Solar"]["genTransCapCredits"]\
         + outData["Solar"]["otherCapCreditsPatroDivident"]\
         + outData["Solar"]["extraItems"]
        # E37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71), update after Form 7 model
        outData["BAU"]["nonPowerCosts"] = outData["BAU"]["transExpense"] \
         + outData["BAU"]["distriExpenseO"] \
         + outData["BAU"]["distriExpenseM"] \
         + outData["BAU"]["customerAccountExpense"] \
         + outData["BAU"]["customerServiceExpense"] \
         + outData["BAU"]["salesExpense"] \
         + outData["BAU"]["adminGeneralExpense"] \
         + outData["BAU"]["depreAmortiExpense"] \
         + outData["BAU"]["taxExpensePG"] \
         + outData["BAU"]["taxExpense"] \
         + outData["BAU"]["interestLongTerm"] \
         + outData["BAU"]["interestConstruction"] \
         + outData["BAU"]["interestExpense"] \
         + outData["BAU"]["otherDeductions"] \
         - (outData["BAU"]["nonOpMarginInterest"] \
         + outData["BAU"]["fundsUsedConstruc"] \
         + outData["BAU"]["incomeEquityInvest"] \
         + outData["BAU"]["nonOpMarginOther"] \
         + outData["BAU"]["genTransCapCredits"] \
         + outData["BAU"]["otherCapCreditsPatroDivident"] \
         + outData["BAU"]["extraItems"])
        # E42 = E63/E24, update after Form 7 model
        outData["BAU"]["costofService"] = outData["BAU"][
            "totalCostElecService"] / outData["BAU"]["totalKWhSales"]
        # F37 = SUM(E48:E54)+SUM(E56:E62)-SUM(E65:E71) = E37, update after Form 7 model
        outData["Solar"]["nonPowerCosts"] = outData["BAU"]["nonPowerCosts"]
        # F42 = F63/F24, update after Form 7 model
        outData["Solar"]["costofService"] = outData["Solar"][
            "totalCostElecService"] / outData["Solar"]["totalKWhSales"]
        # Stdout/stderr.
        outData["stdout"] = "Success"
        outData["stderr"] = ""
        # Write the output.
        with open(pJoin(modelDir, "allOutputData.json"), "w") as outFile:
            json.dump(outData, outFile, indent=4)
        # Update the runTime in the input file.
        endTime = dt.datetime.now()
        inputDict["runTime"] = str(
            dt.timedelta(seconds=int((endTime - startTime).total_seconds())))
        with open(pJoin(modelDir, "allInputData.json"), "w") as inFile:
            json.dump(inputDict, inFile, indent=4)
    except:
        # If input range wasn't valid delete output, write error to disk.
        thisErr = traceback.format_exc()
        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)
        try:
            os.remove(pJoin(modelDir, "allOutputData.json"))
        except Exception, e:
            pass