+
{{ allOutputDataDict['traditionalRuntime'] }}
Traditional Hosting Capacity Map
diff --git a/omf/models/hostingCapacity.py b/omf/models/hostingCapacity.py
index 20c2194e7..e65cc58a3 100644
--- a/omf/models/hostingCapacity.py
+++ b/omf/models/hostingCapacity.py
@@ -1,6 +1,5 @@
''' Calculate hosting capacity using traditional and/or AMI-based methods. '''
import shutil
-from os.path import join as pJoin
import plotly as py
import plotly.express as px
import plotly.graph_objects as go
@@ -50,38 +49,39 @@ def work(modelDir, inputDict):
def run_ami_algorithm(modelDir, inputDict, outData):
# mohca data-driven hosting capacity
- with open(Path(modelDir,inputDict['inputDataFileName']),'w', newline='') as pv_stream:
- pv_stream.write(inputDict['inputDataFileContent'])
- inputPath = Path(modelDir, inputDict['inputDataFileName'])
+ inputPath = Path(modelDir, inputDict['AMIDataFileName'])
+ inputAsString = inputPath.read_text()
try:
- csvValidateAndLoad(inputDict['inputDataFileContent'], modelDir=modelDir, header=0, nrows=None, ncols=5, dtypes=[str, pd.to_datetime, float, float, float], return_type='df', ignore_nans=False, save_file=None, ignore_errors=False )
+ csvValidateAndLoad(inputAsString, modelDir=modelDir, header=0, nrows=None, ncols=5, dtypes=[str, pd.to_datetime, float, float, float], return_type='df', ignore_nans=False, save_file=None, ignore_errors=False )
except:
errorMessage = "AMI-Data CSV file is incorrect format. Please see valid format definition at
OMF Wiki hostingCapacity"
raise Exception(errorMessage)
- outputPath = Path(modelDir, 'mohcaOutput.csv')
- mohcaOutput = []
- mohca_start_time = time.time()
- if inputDict[ "mohcaAlgorithm" ] == "sandia1":
- mohcaOutput = mohca_cl.sandia1( inputPath, outputPath )
- elif inputDict[ "mohcaAlgorithm" ] == "sandia2":
- mohcaOutput = mohca_cl.sandia2( inputPath, outputPath )
+ outputPath = Path(modelDir, 'AMI_output.csv')
+ AMI_output = []
+ AMI_start_time = time.time()
+ if inputDict[ "algorithm" ] == "sandia1":
+ AMI_output = mohca_cl.sandia1( inputPath, outputPath )
+ elif inputDict[ "algorithm" ] == "iastate":
+ AMI_output = mohca_cl.iastate( inputPath, outputPath )
else:
errorMessage = "Algorithm name error"
raise Exception(errorMessage)
- mohca_end_time = time.time()
- mohcaResults = mohcaOutput[0].rename(columns={'kW_hostable': 'voltage_cap_kW'})
- mohcaHistogramFigure = px.histogram( mohcaResults, x='voltage_cap_kW', template="simple_white", color_discrete_sequence=["MediumPurple"] )
- mohcaHistogramFigure.update_layout(bargap=0.5)
+ AMI_end_time = time.time()
+ AMI_results = AMI_output[0].rename(columns={'kW_hostable': 'voltage_cap_kW'})
+ histogramFigure = px.histogram( AMI_results, x='voltage_cap_kW', template="simple_white", color_discrete_sequence=["MediumPurple"] )
+ histogramFigure.update_layout(bargap=0.5)
# TBD - Needs to be modified when the MoHCA algorithm supports calculating thermal hosting capacity
- mohcaResults['thermal_cap_kW'] = [7.23, 7.34, 7.45, 7.53, 7.24, 6.24, 7.424, 7.23 ]
- mohcaResults['max_cap_allowed_kW'] = np.minimum( mohcaResults['voltage_cap_kW'], mohcaResults['thermal_cap_kW'])
- mohcaBarChartFigure = px.bar(mohcaResults, x='busname', y=['voltage_cap_kW', 'thermal_cap_kW', 'max_cap_allowed_kW'], barmode='group', color_discrete_sequence=["green", "lightblue", "MediumPurple"], template="simple_white" )
- mohcaBarChartFigure.add_traces( list(px.line(mohcaResults, x='busname', y='max_cap_allowed_kW', markers=True).select_traces()) )
- outData['mohcaHistogramFigure'] = json.dumps( mohcaHistogramFigure, cls=py.utils.PlotlyJSONEncoder )
- outData['mohcaBarChartFigure'] = json.dumps( mohcaBarChartFigure, cls=py.utils.PlotlyJSONEncoder )
- outData['mohcaHCTableHeadings'] = mohcaResults.columns.values.tolist()
- outData['mohcaHCTableValues'] = ( list(mohcaResults.sort_values( by="max_cap_allowed_kW", ascending=False, ignore_index=True ).itertuples(index=False, name=None)) )
- outData['mohcaRuntime'] = mohca_end_time - mohca_start_time
+ min_value = 5
+ max_value = 8
+ AMI_results['thermal_cap_kW'] = np.random.randint(min_value, max_value + 1, size=len(AMI_results))
+ AMI_results['max_cap_allowed_kW'] = np.minimum( AMI_results['voltage_cap_kW'], AMI_results['thermal_cap_kW'])
+ barChartFigure = px.bar(AMI_results, x='busname', y=['voltage_cap_kW', 'thermal_cap_kW', 'max_cap_allowed_kW'], barmode='group', color_discrete_sequence=["green", "lightblue", "MediumPurple"], template="simple_white" )
+ barChartFigure.add_traces( list(px.line(AMI_results, x='busname', y='max_cap_allowed_kW', markers=True).select_traces()) )
+ outData['histogramFigure'] = json.dumps( histogramFigure, cls=py.utils.PlotlyJSONEncoder )
+ outData['barChartFigure'] = json.dumps( barChartFigure, cls=py.utils.PlotlyJSONEncoder )
+ outData['AMI_tableHeadings'] = AMI_results.columns.values.tolist()
+ outData['AMI_tableValues'] = ( list(AMI_results.sort_values( by="max_cap_allowed_kW", ascending=False, ignore_index=True ).itertuples(index=False, name=None)) )
+ outData['AMI_runtime'] = AMI_end_time - AMI_start_time
def run_traditional_algorithm(modelDir, inputDict, outData):
@@ -136,6 +136,7 @@ def run_traditional_algorithm(modelDir, inputDict, outData):
outData['traditionalHCTableHeadings'] = tradHCDF.columns.values.tolist()
outData['traditionalHCTableValues'] = (list(tradHCDF.itertuples(index=False, name=None)))
outData['traditionalRuntime'] = traditional_end_time - traditional_start_time
+ outData['traditionalHCResults'] = traditionalHCResults
def runtimeEstimate(modelDir):
@@ -145,13 +146,13 @@ def runtimeEstimate(modelDir):
def new(modelDir):
''' Create a new instance of this model. Returns true on success, false on failure. '''
meter_file_name = 'mohcaInputCustom.csv'
- meter_file_path = Path(omf.omfDir,'static','testFiles', meter_file_name)
- meter_file_contents = open(meter_file_path).read()
+ meter_file_path = Path(omf.omfDir,'static','testFiles', 'hostingCapacity', meter_file_name)
+ # meter_file_contents = open(meter_file_path).read()
defaultInputs = {
"modelType": modelName,
- "mohcaAlgorithm": 'sandia1',
- "inputDataFileName": meter_file_name,
- "inputDataFileContent": meter_file_contents,
+ "algorithm": 'sandia1',
+ "AMIDataFileName": meter_file_name,
+ "userAMIDisplayFileName": meter_file_name,
"feederName1": 'iowa240.clean.dss',
"optionalCircuitFile": 'on',
"traditionalHCMaxTestkw": 50000,
@@ -162,6 +163,7 @@ def new(modelDir):
shutil.copyfile(
Path(__neoMetaModel__._omfDir, "static", "publicFeeders", defaultInputs["feederName1"]+'.omd'),
Path(modelDir, defaultInputs["feederName1"]+'.omd'))
+ shutil.copyfile( meter_file_path, Path(modelDir, meter_file_name) )
except:
return False
return creationCode
diff --git a/omf/models/microgridDesign.py b/omf/models/microgridDesign.py
index bd7e27b56..fd0f1c923 100644
--- a/omf/models/microgridDesign.py
+++ b/omf/models/microgridDesign.py
@@ -1,6 +1,7 @@
''' Design microgrid with optimal generation mix for economics and/or reliability. '''
import warnings, csv, json
-from os.path import join as pJoin
+from io import StringIO
+from pathlib import Path
import numpy as np
import pandas as pd
import xlwt
@@ -31,40 +32,18 @@ def work(modelDir, inputDict):
outData['battery'] = inputDict['battery']
outData['year'] = inputDict['year']
outData['urdbLabelSwitch'] = inputDict['urdbLabelSwitch']
-
- # Setting up the loadShape file.
- with open(pJoin(modelDir,"loadShape.csv"),"w") as loadShapeFile:
- loadShapeFile.write(inputDict['loadShape'])
-
- try:
- loadShape = []
- with open(pJoin(modelDir,"loadShape.csv"), newline='') as inFile:
- reader = csv.reader(inFile)
- for row in reader:
- loadShape.append(row)
- if len(loadShape)!=8760: raise Exception
- except:
- errorMessage = "Loadshape CSV file is incorrect format. Please see valid format definition at
OMF Wiki demandResponse"
- raise Exception(errorMessage)
-
- # Setting up the criticalLoadShape file.
- # ToDo: make a condition to make criticalLoadShape file optional, and not needed in default
- # make a switch for "User supplying critical loadshape?"
- # if "User supplying critical loadshape?" = True:
- with open(pJoin(modelDir,"criticalLoadShape.csv"),"w") as criticalLoadShapeFile:
- criticalLoadShapeFile.write(inputDict['criticalLoadShape'])
-
- try:
- criticalLoadShape = []
- with open(pJoin(modelDir,"criticalLoadShape.csv"), newline='') as inFile:
- reader = csv.reader(inFile)
- for row in reader:
- criticalLoadShape.append(row)
- if len(criticalLoadShape)!=8760: raise Exception
- except:
- errorMessage = "Critical Loadshape CSV file is incorrect format. Please see valid format definition at
OMF Wiki demandResponse"
- raise Exception(errorMessage)
-
+ # - Write loadShape.csv
+ load_df = pd.read_csv(StringIO(inputDict['loadShape']), header=None)
+ if load_df.shape[0] != 8760:
+ raise Exception("Loadshape CSV file is incorrect format. Please see valid format definition at
OMF Wiki demandResponse")
+ with (Path(modelDir).resolve(True) / 'loadShape.csv').open('w') as f:
+ f.write(inputDict['loadShape'])
+ # - Write criticalLoadShape.csv
+ critical_load_df = pd.read_csv(StringIO(inputDict['criticalLoadShape']), header=None)
+ if critical_load_df.shape[0] != 8760:
+ raise Exception("Critical Loadshape CSV file is incorrect format. Please see valid format definition at
OMF Wiki demandResponse")
+ with (Path(modelDir).resolve(True) / 'criticalLoadShape.csv').open('w') as f:
+ f.write(inputDict['criticalLoadShape'])
latitude = float(inputDict['latitude'])
longitude = float(inputDict['longitude'])
energyCost = float(inputDict['energyCost'])
@@ -81,7 +60,6 @@ def work(modelDir, inputDict):
analysisYears = int(inputDict['analysisYears'])
discountRate = float(inputDict['discountRate'])
max_runtime = int(inputDict['maxRuntimeSeconds'])
- criticalLoadFactor = float(inputDict['criticalLoadFactor'])
solarMacrsOptionYears = int(inputDict['solarMacrsOptionYears'])
windMacrsOptionYears = int(inputDict['windMacrsOptionYears'])
batteryMacrsOptionYears = int(inputDict['batteryMacrsOptionYears'])
@@ -127,11 +105,6 @@ def work(modelDir, inputDict):
solarCanCurtail = True
elif inputDict['solarCanCurtail'] == "false":
solarCanCurtail = False
- userCriticalLoadShape = bool(inputDict['userCriticalLoadShape'])
- if inputDict['userCriticalLoadShape'] == "true":
- userCriticalLoadShape = True
- elif inputDict['userCriticalLoadShape'] == "false":
- userCriticalLoadShape = False
dieselMax = float(inputDict['dieselMax'])
dieselMin = float(inputDict['dieselMin'])
dieselFuelCostGal = float(inputDict['dieselFuelCostGal'])
@@ -139,30 +112,16 @@ def work(modelDir, inputDict):
dieselOMCostKw = float(inputDict['dieselOMCostKw'])
dieselOMCostKwh = float(inputDict['dieselOMCostKwh'])
dieselOnlyRunsDuringOutage = bool(inputDict['dieselOnlyRunsDuringOutage'])
- if inputDict['dieselOnlyRunsDuringOutage'] == "true":
- dieselOnlyRunsDuringOutage = True
- elif inputDict['dieselOnlyRunsDuringOutage'] == "false":
- dieselOnlyRunsDuringOutage = False
-
- #outageStart = int(inputDict['outageStart'])
- #outageEnd = outageStart + indexStringnt(inputDict['outageDuration'])
- #if outageEnd > 8759:
- #outageEnd = 8759
- #singleOutage = True
- #if str(inputDict['outageType']) == 'annual':
- #singleOutage = False
-
- loadShape = np.array(loadShape)
- criticalLoadShape = np.array(criticalLoadShape)
+ tolerance = float(inputDict['solverTolerance'])
+ loadShape = np.array(load_df)
+ criticalLoadShape = np.array(critical_load_df)
numRows = loadShape.shape[0]
numCols = loadShape.shape[1]
outData['numScenarios'] = numCols+1
-
totalLoad = np.zeros(numRows)
totalCriticalLoad = np.zeros(numRows)
for i in range(0,1+numCols):
indexString = str(i+1)
-
if i == numCols:
load = totalLoad
criticalLoad = totalCriticalLoad
@@ -171,12 +130,10 @@ def work(modelDir, inputDict):
# print(type(load), load[0], load )
load = [float(x) for x in load]
totalLoad = np.add(totalLoad, load)
-
criticalLoad = criticalLoadShape[:,i]
# print(type(load), load[0], load )
criticalLoad = [float(x) for x in criticalLoad]
totalCriticalLoad = np.add(totalCriticalLoad, criticalLoad)
-
jsonifiableLoad = list(load)
jsonifiableCriticalLoad = list(criticalLoad)
@@ -220,7 +177,7 @@ def work(modelDir, inputDict):
#"federal_itc_pct": solarItcPercent
},
"ElectricStorage": { #"Storage": {
- "installed_cost_per_kwh": batteryPowerCost,
+ "installed_cost_per_kw": batteryPowerCost,
#"installed_cost_us_dollars_per_kw": batteryPowerCost,
"installed_cost_per_kwh": batteryCapacityCost,
#"installed_cost_us_dollars_per_kwh": batteryCapacityCost,
@@ -262,64 +219,54 @@ def work(modelDir, inputDict):
# scenario['Scenario']['Site']['ElectricTariff']['blended_monthly_rates_us_dollars_per_kwh'] = energyCostMonthly
# scenario['Scenario']['Site']['ElectricTariff']['blended_monthly_demand_charges_us_dollars_per_kw'] = demandCostMonthly
# solar and battery have default 'max_kw' == 1000000000; Wind has default 'max_kw' == 0 and thus must be set explicitly; Check https://developer.nrel.gov/docs/energy-optimization/reopt-v1 for updates
+ scenario['PV']['existing_kw'] = solarExisting
if solar == 'off':
scenario['PV']['max_kw'] = 0
elif solar == 'on':
scenario['PV']['max_kw'] = solarMax
- scenario['PV']['existing_kw'] = solarExisting
scenario['ElectricLoad']['loads_kw_is_net'] = False
# To turn off energy export/net-metering, set wholesaleCost to "0" and excess PV gen will be curtailed
if solarCanExport == False:
#scenario['Scenario']['ElectricTariff']["wholesale_rate_above_site_load_us_dollars_per_kwh"] = 0
scenario['ElectricTariff']['wholesale_rate'] = 0
#["wholesale_rate_us_dollars_per_kwh"] = 0
- if wind == 'off':
- scenario['Wind']['max_kw'] = 0
- elif wind == 'on':
- scenario['Wind']['max_kw'] = windMax
- if battery == 'off':
- scenario['ElectricStorage']['max_kw'] = 0
- scenario['ElectricStorage']['max_kwh'] = 0 #May not be a needed constraint, even though it is stated as such in the NREL docs
- elif battery == 'on':
- scenario['ElectricStorage']['max_kw'] = batteryPowerMax
- scenario['ElectricStorage']['max_kwh'] = batteryCapacityMax
+ scenario['Wind']['max_kw'] = windMax
+ scenario['ElectricStorage']['max_kw'] = batteryPowerMax
+ scenario['ElectricStorage']['max_kwh'] = batteryCapacityMax
# if outage_start_hour is > 0, a resiliency optimization that includes diesel is triggered
run_outages = True if outage_start_hour != 0 else False
- if run_outages:
- #scenario['Scenario']['LoadProfile']['outage_is_major_event'] = True
- scenario['ElectricLoad']['critical_load_fraction'] = criticalLoadFactor
- #['LoadProfile']['critical_load_pct'] = criticalLoadFactor
- scenario['ElectricUtility'] = {}
- scenario['ElectricUtility']['outage_start_time_step'] = outage_start_hour
- #['LoadProfile']['outage_start_time_step'] = outage_start_hour
- scenario['ElectricUtility']['outage_end_time_step'] = outage_end_hour
- #['LoadProfile']['outage_end_time_step'] = outage_end_hour
- scenario['Generator']['fuel_avail_gal'] = fuelAvailable
- scenario['Generator']['min_turn_down_fraction'] = minGenLoading
- #['min_turn_down_pct'] = minGenLoading
- scenario['Generator']['existing_kw'] = genExisting
- scenario['Generator']['fuel_cost_per_gallon'] = dieselFuelCostGal
- #['diesel_fuel_cost_us_dollars_per_gallon'] = dieselFuelCostGal
- scenario['Generator']['emissions_factor_lb_CO2_per_gal'] = dieselCO2Factor
- scenario['Generator']['om_cost_per_kw'] = dieselOMCostKw
- #['om_cost_us_dollars_per_kw'] = dieselOMCostKw
- scenario['Generator']['om_cost_per_kwh'] = dieselOMCostKwh
- #['om_cost_us_dollars_per_kwh'] = dieselOMCostKwh
- # use userCriticalLoadShape only if True, else model defaults to criticalLoadFactor
- if userCriticalLoadShape == True:
- scenario['ElectricLoad']['critical_loads_kw'] = jsonifiableCriticalLoad
- # diesel has a quirk in how it gets inputted to REopt such that when strictly specified, allOutputData["sizeDiesel1"] = allInputData['dieselMax'] + allInputData['genExisting']
- #todo: check if still true for reopt.jl
- if dieselMax - genExisting > 0:
- scenario['Generator']['max_kw'] = dieselMax - genExisting
- else:
- scenario['Generator']['max_kw'] = 0
- if dieselMin - genExisting > 0:
- scenario['Generator']['min_kw'] = dieselMin - genExisting
- else:
- scenario['Generator']['min_kw'] = 0
- #adding outage results (REopt.jl)
- #scenario['ElectricUtility']['outage_durations'] = [ outage_duration ] #not sure if correct
+ if outage_start_hour == 0:
+ outage_end_hour = 0
+ #scenario['Scenario']['LoadProfile']['outage_is_major_event'] = True
+ scenario['ElectricUtility'] = {}
+ scenario['ElectricUtility']['outage_start_time_step'] = outage_start_hour
+ #['LoadProfile']['outage_start_time_step'] = outage_start_hour
+ scenario['ElectricUtility']['outage_end_time_step'] = outage_end_hour
+ #['LoadProfile']['outage_end_time_step'] = outage_end_hour
+ scenario['Generator']['fuel_avail_gal'] = fuelAvailable
+ scenario['Generator']['min_turn_down_fraction'] = minGenLoading
+ #['min_turn_down_pct'] = minGenLoading
+ scenario['Generator']['existing_kw'] = genExisting
+ scenario['Generator']['fuel_cost_per_gallon'] = dieselFuelCostGal
+ #['diesel_fuel_cost_us_dollars_per_gallon'] = dieselFuelCostGal
+ scenario['Generator']['emissions_factor_lb_CO2_per_gal'] = dieselCO2Factor
+ scenario['Generator']['om_cost_per_kw'] = dieselOMCostKw
+ #['om_cost_us_dollars_per_kw'] = dieselOMCostKw
+ scenario['Generator']['om_cost_per_kwh'] = dieselOMCostKwh
+ #['om_cost_us_dollars_per_kwh'] = dieselOMCostKwh
+ scenario['ElectricLoad']['critical_loads_kw'] = jsonifiableCriticalLoad
+ # diesel has a quirk in how it gets inputted to REopt such that when strictly specified, allOutputData["sizeDiesel1"] = allInputData['dieselMax'] + allInputData['genExisting']
+ #todo: check if still true for reopt.jl
+ #if dieselMax - genExisting > 0:
+ # scenario['Generator']['max_kw'] = dieselMax - genExisting
+ #else:
+ # scenario['Generator']['max_kw'] = 0
+ #if dieselMin - genExisting > 0:
+ # scenario['Generator']['min_kw'] = dieselMin - genExisting
+ #else:
+ # scenario['Generator']['min_kw'] = 0
+ #adding outage results (REopt.jl)
+ #scenario['ElectricUtility']['outage_durations'] = [ outage_duration ] #not sure if correct
# set rates
if urdbLabelSwitch == 'off':
@@ -335,7 +282,7 @@ def work(modelDir, inputDict):
json.dump(scenario, jsonFile)
# Run REopt API script *** => switched to REopt.jl
- reopt_jl.run_reopt_jl(modelDir, "Scenario_test_POST.json", outages=run_outages, max_runtime_s = max_runtime )
+ reopt_jl.run_reopt_jl(modelDir, "Scenario_test_POST.json", outages=run_outages, max_runtime_s = max_runtime, tolerance = tolerance)
with open(pJoin(modelDir, 'results.json')) as jsonFile:
results = json.load(jsonFile)
@@ -438,7 +385,7 @@ def work(modelDir, inputDict):
outData['macrsFiveYear' + indexString] = reopt_inputs['s']['financial']['macrs_five_year']
outData['macrsSevenYear' + indexString] = reopt_inputs['s']['financial']['macrs_seven_year']
- if solar == 'on':
+ if 'PV' in results:
outData['sizePV' + indexString] = results['PV']['size_kw']
outData['sizePVRounded' + indexString] = round(results['PV']['size_kw'],1)
outData['powerPVToBattery' + indexString] = results['PV']['electric_to_storage_series_kw']#['year_one_to_battery_series_kw']
@@ -486,8 +433,8 @@ def work(modelDir, inputDict):
else:
outData['sizePV' + indexString] = 0
outData['sizePVRounded' + indexString] = 0
-
- if battery == 'on':
+
+ if 'ElectricStorage' in results:
outData['powerBattery' + indexString] = results['ElectricStorage']['size_kw']
#['Storage']['size_kw']
outData['powerBatteryRounded' + indexString] = round(results['ElectricStorage']['size_kw'],1)
@@ -536,8 +483,8 @@ def work(modelDir, inputDict):
outData['capacityBattery' + indexString] = 0
outData['powerBatteryRounded' + indexString] = 0
outData['capacityBatteryRounded' + indexString] = 0
-
- if wind == 'on':
+
+ if 'Wind' in results:
outData['sizeWind' + indexString] = results['Wind']['size_kw']
outData['sizeWindRounded' + indexString] = round(results['Wind']['size_kw'],1)
outData['powerWindToBattery' + indexString] = results['Wind']['electric_to_storage_series_kw']
@@ -777,7 +724,7 @@ def write_table(table, name, start_row, start_col):
write_table(proforma_tax_insurance, "TAX AND INSURANCE PARAMETERS",excel_row,excel_col)
excel_row += len(proforma_tax_insurance) + 2
- if solar == "on":
+ if 'PV' in results:
proforma_tax_credits = [
#note: removing values from table that are not included in reopt.jl calculations
['Investment tax credit (ITC)', '' ],
@@ -806,7 +753,7 @@ def write_table(table, name, start_row, start_col):
write_table(proforma_cash_incentives, 'PV DIRECT CASH INCENTIVES',excel_row,excel_col)
excel_row += len(proforma_cash_incentives) + 2
- if wind == "on":
+ if 'Wind' in results:
proforma_tax_credits = [
['Investment tax credit (ITC)', '' ],
['As percentage', '%' ],
@@ -831,7 +778,7 @@ def write_table(table, name, start_row, start_col):
write_table(proforma_cash_incentives, 'WIND DIRECT CASH INCENTIVES',excel_row,excel_col)
excel_row += len(proforma_cash_incentives) + 2
- if battery == "on":
+ if 'ElectricStorage' in results:
proforma_tax_credits = [
['Investment tax credit (ITC)', '' ],
['As percentage', '%' ],
@@ -860,15 +807,15 @@ def add_to_depreciation_proforma(der_type, years, bonus_fraction):
depreciation_proforma[1].append(years)
depreciation_proforma[2].append(bonus_fraction)
- if solar == "on":
+ if 'PV' in results:
pv_bonus_fraction = outData['pvMacrsBonusFraction' + indexString]
add_to_depreciation_proforma("PV",str(solarMacrsOptionYears), pv_bonus_fraction)
- if battery == "on":
+ if 'ElectricStorage' in results:
battery_bonus_fraction = outData['batteryMacrsBonusFraction' + indexString]
add_to_depreciation_proforma("BATTERY",str(batteryMacrsOptionYears), battery_bonus_fraction)
- if wind == "on":
+ if 'Wind' in results:
wind_bonus_fraction = outData['windMacrsBonusFraction' + indexString]
add_to_depreciation_proforma("WIND", str(windMacrsOptionYears), wind_bonus_fraction)
@@ -958,15 +905,15 @@ def makeGridLine(x,y,color,name):
powerGridToLoad = makeGridLine(x_values,outData['powerGridToLoad' + indexString],'blue','Load met by Grid')
plotData.append(powerGridToLoad)
- if solar == 'on':
+ if 'PV' in results:
powerPVToLoad = makeGridLine(x_values,outData['powerPVToLoad' + indexString],'yellow','Load met by Solar')
plotData.append(powerPVToLoad)
- if battery == 'on':
+ if 'ElectricStorage' in results:
powerBatteryToLoad = makeGridLine(x_values,outData['powerBatteryToLoad' + indexString],'gray','Load met by Battery')
plotData.append(powerBatteryToLoad)
- if wind == 'on':
+ if 'Wind' in results:
powerWindToLoad = makeGridLine(x_values,outData['powerWindToLoad' + indexString],'purple','Load met by Wind')
plotData.append(powerWindToLoad)
@@ -980,7 +927,7 @@ def makeGridLine(x,y,color,name):
outData["plotlyLayout"] = json.dumps(plotlyLayout, cls=plotly.utils.PlotlyJSONEncoder)
plotData = []
- if solar == 'on':
+ if 'PV' in results:
powerPVToLoad = makeGridLine(x_values,outData['powerPVToLoad' + indexString],'yellow','Solar used to meet Load')
plotData.append(powerPVToLoad)
@@ -990,7 +937,7 @@ def makeGridLine(x,y,color,name):
powerPVCurtailed = makeGridLine(x_values,outData['powerPVCurtailed' + indexString],'red','Solar power curtailed')
plotData.append(powerPVCurtailed)
- if battery == 'on':
+ if 'ElectricStorage' in results:
powerPVToBattery = makeGridLine(x_values,outData['powerPVToBattery' + indexString],'gray','Solar used to charge Battery')
plotData.append(powerPVToBattery)
@@ -1005,11 +952,11 @@ def makeGridLine(x,y,color,name):
plotData = []
- if wind == 'on':
+ if 'Wind' in results:
powerWindToLoad = makeGridLine(x_values,outData['powerWindToLoad' + indexString],'purple','Wind used to meet Load')
plotData.append(powerWindToLoad)
- if battery == 'on':
+ if 'ElectricStorage' in results:
powerWindToBattery = makeGridLine(x_values,outData['powerWindToBattery' + indexString],'gray','Wind used to charge Battery')
plotData.append(powerWindToBattery)
@@ -1027,7 +974,7 @@ def makeGridLine(x,y,color,name):
powerDieselToLoad = makeGridLine(x_values,outData['powerDieselToLoad' + indexString],'brown','Fossil Gen used to meet Load')
plotData.append(powerDieselToLoad)
- if battery == 'on':
+ if 'ElectricStorage' in results:
powerDieselToBattery = makeGridLine(x_values,outData['powerDieselToBattery' + indexString],'gray','Fossil Gen used to charge Battery')
plotData.append(powerDieselToBattery)
@@ -1041,15 +988,15 @@ def makeGridLine(x,y,color,name):
outData["dieselData" + indexString] = json.dumps(plotData, cls=plotly.utils.PlotlyJSONEncoder)
plotData = []
- if battery == 'on':
+ if 'ElectricStorage' in results:
powerGridToBattery = makeGridLine(x_values,outData['powerGridToBattery' + indexString],'blue','Grid')
plotData.append(powerGridToBattery)
- if solar == 'on':
+ if 'PV' in results:
powerPVToBattery = makeGridLine(x_values,outData['powerPVToBattery' + indexString],'yellow','Solar')
plotData.append(powerPVToBattery)
- if wind == 'on':
+ if 'Wind' in results:
powerWindToBattery = makeGridLine(x_values,outData['powerWindToBattery' + indexString],'purple','Wind')
plotData.append(powerWindToBattery)
@@ -1061,7 +1008,7 @@ def makeGridLine(x,y,color,name):
outData["batteryData" + indexString] = json.dumps(plotData, cls=plotly.utils.PlotlyJSONEncoder)
plotData = []
- if battery == 'on':
+ if 'ElectricStorage' in results:
chargeLevelBattery = go.Scatter(
x=pd.to_datetime(x, unit = 'h', origin = pd.Timestamp(f'{year}-01-01')),
y=outData['chargeLevelBattery' + indexString],
@@ -1112,7 +1059,6 @@ def new(modelDir):
fName = "input - 200 Employee Office, Springfield Illinois, 2001.csv"
with open(pJoin(omf.omfDir, "static", "testFiles", fName)) as f:
load_shape = f.read()
-
cfName = "critical_load_test.csv"
with open(pJoin(omf.omfDir, "static", "testFiles", cfName)) as f:
crit_load_shape = f.read()
@@ -1170,8 +1116,6 @@ def new(modelDir):
"batteryCapacityMax": "1000000",
"dieselMax": "100000",
"solarExisting": 0,
- "userCriticalLoadShape": False,
- "criticalLoadFactor": ".5",
"outage_start_hour": "500",
"outageDuration": "24",
"fuelAvailable": "20000",
diff --git a/omf/models/resilientCommunity.html b/omf/models/resilientCommunity.html
index 2cf4c91b2..b2a2de0cd 100644
--- a/omf/models/resilientCommunity.html
+++ b/omf/models/resilientCommunity.html
@@ -37,11 +37,67 @@
+
+