Skip to content

Commit

Permalink
Added default inputs to derConsumer.py and .html
Browse files Browse the repository at this point in the history
  • Loading branch information
astronobri committed Apr 22, 2024
1 parent b06c660 commit 23c7ad1
Show file tree
Hide file tree
Showing 4 changed files with 17,756 additions and 15 deletions.
164 changes: 159 additions & 5 deletions omf/models/derConsumer.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,170 @@
</div>
<!-- Model Specific Inputs -->
<div class="wideInput">
<p class="inputSectionHeader">System Parameters</p>
<p class="inputSectionHeader">Specific REopt Model Inputs</p>
</div>
<hr style="border-style: solid; border-color: #196b12; margin-top: 10px;">
<div class="shortInput">
<label class="tooltip">Demand Curve (.csv file)<span class="classic">Please see the documentation at the green 'Help?' link above for the required format and an example file.</span></label>
<input id="demandCurveFile" type="file" style="display:none" onchange="handle_files(this.files,'demandCurve','fileName')">
<input id="demandCurve" name="demandCurve" value="{{allInputDataDict.demandCurve}}" type="hidden">
<div>
<label for="demandCurveFile" class="fileButton">Choose File</label>
<input id="fileName" name="fileName" value="{{allInputDataDict.fileName}}" value='' readonly class="uploadFileName">
</div>
</div>
<div class="shortInput">
<label class="tooltip">Temperature Curve in &degC (.csv file)<span class="classic">Please see the documentation at the help link for the required format and an example temperature file.</span></label>
<input id="tempCurveFile" type="file" style="display:none" onchange="handle_files(this.files,'tempCurve','tempFileName')">
<input id="tempCurve" name="tempCurve" value="{{allInputDataDict.tempCurve}}" type="hidden">
<div>
<label for="tempCurveFile" class="fileButton">Choose File</label>
<input id="tempFileName" name="tempFileName" value="{{allInputDataDict.tempFileName}}" value='' readonly class="uploadFileName">
</div>
</div>
<div class="shortInput">
<label class="tooltip">Latitude<span class="classic">Specify the latitude of the load/grid.</span></label>
<input type="text" id="latitude" name="latitude" value="{{allInputDataDict.latitude}}" pattern="^\-?\d+\.?\d*?$" required="required"/>
</div>
<div class="shortInput">
<label class="tooltip">Longitude<span class="classic">Specify the longitude of the load/grid.</span></label>
<input type="text" id="longitude" name="longitude" value="{{allInputDataDict.longitude}}" pattern="^\-?\d+\.?\d*?$" required="required"/>
</div>
<div class="shortInput">
<label class="tooltip">URDB Label<span class="classic">Input the string found at the end of the URDB Rate URL, For example https://openei.org/apps/<br>IURDB/rate/view/<br> 5b75cfe95457a3454faf0aea <br> would yield "5b75cfe95457a3454faf0aea"</span></label>
<input type="text" id="urdbLabel" name="urdbLabel" value="{{allInputDataDict.urdbLabel}}" required="required"/>
</div>
<div class="shortInput">
<label class="tooltip">Year<span class="classic">Specify the year to which the load shape values corresond.</span></label>
<input type="text" id="year" name="year" value="{{allInputDataDict.year}}" pattern="^\d{4}$" required="required"/>
</div>
<div class="shortInput">
<label class="tooltip">Analysis Period (years)<span class="classic">Specify the length of financial analysis in years.</span></label>
<input type="number" id="analysisYears" name="analysisYears" value="{{allInputDataDict.analysisYears}}" step="1" min="2" max="75" required="required"/>
</div>
<hr>
<div class="wideInput"> <!-- REopt technologies-->
<p class="inputSectionHeader" style="font-size: medium;">Model DER technologies</p>
</div>
<div class="shortInput">
<label class="tooltip">PV<span class="classic">Include PV in DER analysis.</span></label>
<select id="PV" name="PV" value="{{allInputDataDict.PV}}"/>
<option value="Yes" {{ 'selected' if allInputDataDict.solar == 'Yes' }}>Yes</option>
<option value="No" {{ 'selected' if allInputDataDict.solar == 'No' }}>No</option>
</select>
</div>
<div class="shortInput">
<label class="tooltip">Battery<span class="classic">Include battery energy storage in DER analysis.</span></label>
<select id="battery" name="battery" value="{{allInputDataDict.BESS}}"/>
<option value="Yes" {{ 'selected' if allInputDataDict.BESS == 'Yes' }}>Yes</option>
<option value="No" {{ 'selected' if allInputDataDict.BESS == 'No' }}>No</option>
</select>
</div>
<div class="shortInput">
<label class="tooltip">Diesel Generator<span class="classic">Include diesel generator in DER analysis.</span></label>
<select id="generator" name="generator" value="{{allInputDataDict.generator}}"/>
<option value="Yes" {{ 'selected' if allInputDataDict.generator == 'Yes' }}>Yes</option>
<option value="No" {{ 'selected' if allInputDataDict.generator == 'No' }}>No</option>
</select>
</div>
<div class="wideInput"> <!-- vbatDispatch Specific Inputs -->
<p class="inputSectionHeader">Specific vbatDispatch Model Inputs</p>
</div>
<hr style="border-style: solid; border-color: #196b12; margin-top: 10px;">
<div class="shortInput">
<label class="tooltip">Load Type<span class="classic">Device to be used in calculations</span></label>
<select id="load_type" onchange="loadDefaultParameters()" name="load_type">
<script type="text/javascript">
function loadDefaultParameters(){
var x = gebi('load_type').value;
if (x == 1){ //AC
gebi('capacitance').value = '2';
gebi('resistance').value = '2';
gebi('power').value = '5.6';
gebi('cop').value = '2.5';
gebi('deadband').value = '0.625';
gebi('setpoint').value = '22.5';
} else if (x == 2){ //HP
gebi('capacitance').value = '2';
gebi('resistance').value = '2';
gebi('power').value = '5.6';
gebi('cop').value = '3.5';
gebi('deadband').value = '0.625';
gebi('setpoint').value = '19.5';
} else if (x == 3) { //RG
gebi('capacitance').value = '0.6';
gebi('resistance').value = '90';
gebi('power').value = '0.3';
gebi('cop').value = '2';
gebi('deadband').value = '1.5';
gebi('setpoint').value = '2.5';
} else { //WH
gebi('capacitance').value = '0.4';
gebi('resistance').value = '120';
gebi('power').value = '4.5';
gebi('cop').value = '1';
gebi('deadband').value = '3';
gebi('setpoint').value = '48.5';
}
}
</script>
<option value="1" {{ 'selected' if allInputDataDict.load_type == '1' }}>Air Conditioner</option>
<option value="2" {{ 'selected' if allInputDataDict.load_type == '2' }}>Heat Pump</option>
<option value="3" {{ 'selected' if allInputDataDict.load_type == '3' }}>Refrigerator</option>
<option value="4" {{ 'selected' if allInputDataDict.load_type == '4' }}>Water Heater</option>
</select>
</div>
<div class="shortInput">
<label class="tooltip">Number of Devices<span class="classic">Total number of devices to simulate. Must be greater than 1</span></label>
<input type="text" id="number_devices" name="number_devices" value="{{allInputDataDict.number_devices}}" pattern="[1-9][0-9]{2,8}" required="required">
</div>
<div class="shortInput">
<label class="tooltip">Rated Power (kW)<span class="classic">Max power per device. Must be a positive rational number between 0.1 and 7.2.</span></label>
<input type="text" id="power" name="power" value="{{allInputDataDict.power}}" pattern="^\d+\.?\d*?$" required="required">
</div>
<div class="shortInput">
<label class="tooltip">Thermal Capacitance (kWh/&degC)<span class="classic">Capacitance of each device. Must be between 0.2 and 2.5 with exactly one decimal digit.</span></label>
<input type="text" id="capacitance" name="capacitance" value="{{allInputDataDict.capacitance}}" pattern="^\d+\.?\d*?$" required="required">
</div>
<div class="shortInput">
<label class="tooltip">Thermal Resistance (&degC/kW)<span class="classic">Resistance of each device. Must be between 1.5 and 140.</span></label>
<input type="text" id="resistance" name="resistance" value="{{allInputDataDict.resistance}}" pattern="^\d+\.?\d*?$" required="required">
</div>
<div class="shortInput">
<label class="tooltip">COP<span class="classic">Coefficient of power of each device. Must be between 1 and 3.5</span></label>
<input type="text" id="cop" name="cop" value="{{allInputDataDict.cop}}" pattern="^\d+\.?\d*?$" required="required">
</div>
<div class="shortInput">
<label class="tooltip">Temperature Setpoint (&degC)<span class="classic">Setpoint for each device. Must be between 1.7 and 54.</span></label>
<input type="text" id="setpoint" name="setpoint" value="{{allInputDataDict.setpoint}}" pattern="^\d+\.?\d*?$" required="required">
</div>
<div class="shortInput">
<label class="tooltip">Temperature Deadband (&degC)<span class="classic">Deadband for each device. Must be between 0.125 and 2.</span></label>
<input type="text" id="deadband" name="deadband" value="{{allInputDataDict.deadband}}" pattern="^\d+\.?\d*?$" required="required">
</div>
<div class="shortInput">
<label class="tooltip">Unit Cost ($/unit)<span class="classic">Cost per device for equipping it to respond to load control signals. E.g. for a direct load control program, this would be the cost of a load control switch, typically about $100.</span></label>
<input type="text" id="unitDeviceCost" name="unitDeviceCost" value="{{allInputDataDict.unitDeviceCost}}" pattern="^\d+\.?\d*?$" required="required">
</div>
<div class="shortInput">
<label class="tooltip">Upkeep Cost ($/unit/year)<span class="classic">Maintenance cost each year per device for replacing or repairing defective load control equipment.</span></label>
<input type="text" id="unitUpkeepCost" name="unitUpkeepCost" value="{{allInputDataDict.unitUpkeepCost}}" pattern="^\d+\.?\d*?$" required="required">
</div>
<div class="shortInput">
<label class="tooltip">Demand Charge Cost ($/kW)<span class="classic">Demand charge utility pays for peak demand events. Assumed to be calculated based on monthly single highest peak.</span></label>
<input type="text" id="demandChargeCost" name="demandChargeCost" value="{{allInputDataDict.demandChargeCost}}" pattern="^\d+\.?\d*?$" required="required">
</div>
<div class="shortInput">
<label class="tooltip">Energy Cost ($/kWh)<span class="classic">Cost of energy bought by the utility. I.e. wholesale (not retail) cost.</span></label>
<input type="text" id="electricityCost" name="electricityCost" value="{{allInputDataDict.electricityCost}}" pattern="^\d+\.?\d*?$" required="required">
</div>
<div class="shortInput">
<label class="tooltip">Input 1<span class="classic">Enter an input of any kind.</span></label>
<input type="text" id="input1" name="input1" value="{{allInputDataDict.input1}}"required="required" placeholder="abc1 Easy as..."/>
<label class="tooltip">Financial Projection Length (years)<span class="classic">Number of years to project out estimated savings.</span></label>
<input type="text" id="projectionLength" name="projectionLength" value="{{allInputDataDict.projectionLength}}" pattern="^\d+\.?\d*?$" required="required">
</div>
<div class="shortInput">
<label class="tooltip">Input 2<span class="classic">Enter an input of another kind.</span></label>
<input type="text" id="input2" name="input2" value="{{allInputDataDict.input2}}"required="required" placeholder="123 Or Simple as.."/>
<label class="tooltip">Discount Rate (%)<span class="classic">Discount rate used in financial analysis.</span></label>
<input type="text" id="discountRate" name="discountRate" value="{{allInputDataDict.discountRate}}" pattern="[1-9][0-9]{0,2}" required="required">
</div>
{{ omfModelButtons }}
</form>
Expand Down
87 changes: 77 additions & 10 deletions omf/models/derConsumer.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
''' A model skeleton for future models: Calculates the sum of two integers. '''
''' Performs cost-benefit analysis for a member-consumer with distributed
energy resource (DER) technologies. '''

import warnings
# warnings.filterwarnings("ignore")

# Python imports
import shutil, datetime
from os.path import join as pJoin
import numpy as np
import pandas as pd

# OMF imports
from omf import feeder
from omf.models.voltageDrop import drawPlot
from omf.models import __neoMetaModel__
from omf.models.__neoMetaModel__ import *
from omf.models import vbatDispatch as vb
from omf.solvers import reopt_jl

# Model metadata:
modelName, template = __neoMetaModel__.metadata(__file__)
Expand Down Expand Up @@ -39,31 +45,91 @@ def castAddInputs(val1,val2):
def work(modelDir, inputDict):
''' Run the model in its directory. '''
# Delete output file every run if it exists
outData = {}
outData = {}

## Read in a static REopt test file
with open(pJoin(__neoMetaModel__._omfDir,"static","testFiles","residential_REopt_results.json")) as f:
results = json.load(f)
print('Successfully read in REopt test file. \n')

# Model operations goes here.
inputOne = inputDict.get("input1", 123)
inputTwo = inputDict.get("input2", 867)
output = str(castAddInputs(inputOne,inputTwo))
outData["output"] = output


# Model operations typically ends here.
# Stdout/stderr.
outData['PV'] = results['outputs']['PV']
outData["stdout"] = "Success"
outData["stderr"] = ""
return outData

def new(modelDir):
''' Create a new instance of this model. Returns true on success, false on failure. '''
with open(pJoin(__neoMetaModel__._omfDir,"static","testFiles","residential_PV_load.csv")) as f:
demand_curve = f.read()
with open(pJoin(__neoMetaModel__._omfDir,"static","testFiles","residential_extended_temperature_data.csv")) as f:
temp_curve = f.read()

defaultInputs = {
"user" : "admin",
## OMF inputs:
"user": "admin",
"modelType": modelName,
"created": str(datetime.datetime.now()),
"user": "admin",
"modelType": modelName,
"input1": "abc1 Easy as...",
"input2": "123 Or Simple as...",
"created":str(datetime.datetime.now())

## REopt inputs:
"latitude": '39.532165', ## Rivesville, WV
"longitude": '-80.120618', ## TODO: Should these be strings or floats?
"year": 2018,
"analysisYears": 25,
"urdbLabel": '643476222faee2f0f800d8b1', ## Rivesville, WV - Monongahela Power
"fileName": "residential_PV_load.csv",
"tempFileName": "residential_extended_temperature_data.csv",
"demandCurve": demand_curve,
"tempCurve": temp_curve,
"outage": False,
"PV": "Yes",
"BESS": "No",
"generator": "No",

## vbatDispatch inputs:
"load_type": 2, ## Heat Pump
"number_devices": 1,
"power": 5.6,
"capacitance": 2,
"resistance": 2,
"cop": 2.5,
"setpoint": 19.5,
"deadband": 0.625,
"demandChargeCost": 25,
"electricityCost": 0.16,
"projectionLength": 25,
"discountRate": 2,
"unitDeviceCost": 150,
"unitUpkeepCost": 5,
}
return __neoMetaModel__.new(modelDir, defaultInputs)

@neoMetaModel_test_setup
def _tests():
# Location
modelLoc = pJoin(__neoMetaModel__._omfDir,"data","Model","admin","Automated Testing of " + modelName)
# Blow away old test results if necessary.
try:
shutil.rmtree(modelLoc)
except:
# No previous test results.
pass
# Create New.
new(modelLoc)
# Pre-run.
__neoMetaModel__.renderAndShow(modelLoc) ## Why is there a pre-run?
# Run the model.
__neoMetaModel__.runForeground(modelLoc)
# Show the output.
__neoMetaModel__.renderAndShow(modelLoc)

def _debugging():
# Location
modelLoc = pJoin(__neoMetaModel__._omfDir,"data","Model","admin","Automated Testing of " + modelName)
# Blow away old test results if necessary.
Expand All @@ -83,4 +149,5 @@ def _tests():

if __name__ == '__main__':
#_tests()
_debugging() ## This is only used to bypass the runAllTests errors due to this model's incompletion. It is just a copy of _tests() function.
pass
Loading

0 comments on commit 23c7ad1

Please sign in to comment.