Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workflow from Comstock/resstock to alfalfa #477

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions tests/models/test_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from workflow.lib.inputs import Inputs
from workflow.lib.models import Models
from pathlib import Path
import pytest
import os
import shutil


def test_model_downloads_comstock():

current_directory = Path(__file__).resolve().parent

# folder to download models
folder_name = Path(os.path.join(current_directory, 'comsstock'))

id = ['bldg0000001','bldg0000002']

objA = Inputs
objA.__init__(Inputs, '2021','comstock_tmy3_release_1','00', id, folder_name)

# remove if folder exists
shutil.rmtree(folder_name, ignore_errors=True)

objB = Models
objB.download_models(objA)

save_folder_1 = os.path.join(folder_name, id[0], 'models', id[0] + '.osm')
workflow_1 = os.path.join(folder_name, id[0], 'workflow.osw')
save_folder_2 = os.path.join(folder_name, id[1], 'models', id[1] + '.osm')
workflow_2 = os.path.join(folder_name, id[1], 'workflow.osw')

# check if models are downloaded
assert os.path.exists(save_folder_1)
assert os.path.exists(save_folder_2)
assert os.path.exists(workflow_1)
assert os.path.exists(workflow_2)

def test_model_downloads_resstock():

current_directory = Path(__file__).resolve().parent

folder_name = Path(os.path.join(current_directory, 'resstock'))
id = ['bldg0000003','bldg0000004']

objA = Inputs
objA.__init__(Inputs, '2021','resstock_tmy3_release_1','00', id, folder_name)

shutil.rmtree(folder_name, ignore_errors=True)

objB = Models
objB.download_models(objA)


save_folder_1 = os.path.join(folder_name, id[0], 'models', id[0] + '.osm')
workflow_1 = os.path.join(folder_name, id[0], 'workflow.osw')
save_folder_2 = os.path.join(folder_name, id[1], 'models', id[1] + '.osm')
workflow_2 = os.path.join(folder_name, id[1], 'workflow.osw')

assert os.path.exists(save_folder_1)
assert os.path.exists(workflow_1)
assert os.path.exists(save_folder_2)
assert os.path.exists(workflow_2)
2 changes: 2 additions & 0 deletions workflow/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Buildstock Alfalfa workflow

Binary file added workflow/base_files/end_use_profiles_mapping.xlsx
Binary file not shown.
1,068 changes: 1,068 additions & 0 deletions workflow/base_files/external_TMY3_sources.csv

Large diffs are not rendered by default.

131 changes: 131 additions & 0 deletions workflow/base_files/measures/alfalfa_vars/measure.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# insert your copyright here

# see the URL below for information on how to write OpenStudio measures
# http://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/

# start the measure
class AlfalfaVariables < OpenStudio::Measure::ModelMeasure
# human readable name
def name
return 'AlfalfaVariables'
end

# human readable description
def description
return 'Add custom variables for Alfalfa'
end

# human readable description of modeling approach
def modeler_description
return 'Add EMS global variables required by Alfalfa'
end

# define the arguments that the user will input
def arguments(model)
args = OpenStudio::Measure::OSArgumentVector.new
return args
end

def create_input(model, name, freq)
# The purpose of this function is to create an Alfalfa input that is accessible via python plugins

global = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, name)
global.setExportToBCVTB(true)

# The global variable's value must be sent to output an variable so that python programs can read it
# don't be mistaken, An OuputVariable object is created, but this is "input" to the simulation, from Alfalfa clients
global_ems_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, global)
global_ems_output.setName(name + "_EMS_Value")
global_ems_output.setUpdateFrequency("SystemTimestep")

# Request the custom ems output var creaed in the previous step
global_output = OpenStudio::Model::OutputVariable.new(global_ems_output.nameString(), model)
global_output.setName(name + "_Value")
global_output.setReportingFrequency(freq)
global_output.setKeyValue("EMS")
# Setting exportToBCVTB to true is optional, and will result in the output variable showing up in the Alfalfa api,
# this might be useful for confirmation of the input
global_output.setExportToBCVTB(true)

# repeat the previous steps for an "Enable" input
# This value will be 1 (instead of 0) anytime a client writes to the input via the Alfalfa api
global_enable = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, name + "_Enable")
global_enable.setExportToBCVTB(true)

global_enable_ems_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, global_enable)
global_enable_ems_output.setName(name + "_Enable_EMS_Value")
global_enable_ems_output.setUpdateFrequency("SystemTimestep")

global_enable_output = OpenStudio::Model::OutputVariable.new(global_enable_ems_output.nameString(), model)
global_enable_output.setName(name + "_Enable_Value")
global_enable_output.setReportingFrequency(freq)
global_enable_output.setKeyValue("EMS")
global_enable_output.setExportToBCVTB(true)
end

def create_output(model, var, key, name, freq)
new_var = OpenStudio::Model::OutputVariable.new(var, model)
new_var.setName(name)
new_var.setReportingFrequency(freq)
new_var.setKeyValue(key)
new_var.setExportToBCVTB(true)
end

# define what happens when the measure is run
def run(model, runner, user_arguments)
super(model, runner, user_arguments)

# Alfalfa inputs
# These can be set through the Alfalfa API, they will be available as OutputVariables
# in the simulation. Use them as you will
# Also see comments on the create_input method
create_input(model, "HVACFanOnOff", "Timestep")
create_input(model, "HVACCompressorOnOff", "Timestep")
create_input(model, "CaseOnOff", "Timestep")
create_input(model, "CaseDoorStatus", "Timestep")
create_input(model, "CaseDefrostStatus", "Timestep")
create_input(model, "CaseAntiSweatStatus", "Timestep")
create_input(model, "CaseLightStatus", "Timestep")
create_input(model, "ZoneLightStatus", "Timestep")
create_input(model, "ZoneOccStatus", "Timestep")
create_input(model, "Test_Point_1", "Timestep")

# Alfalfa outputs
create_output(model, "PythonPlugin:OutputVariable", "mt1_t_case", "MT1 Case Temp", "Timestep")
create_output(model, "PythonPlugin:OutputVariable", "mt2_t_case", "MT2 Case Temp", "Timestep")
create_output(model, "PythonPlugin:OutputVariable", "lt1_t_case", "LT1 Case Temp", "Timestep")
create_output(model, "PythonPlugin:OutputVariable", "lt2_t_case", "LT2 Case Temp", "Timestep")
create_output(model, "PythonPlugin:OutputVariable", "mt1_t_food", "MT1 Prod Temp", "Timestep")
create_output(model, "PythonPlugin:OutputVariable", "mt2_t_food", "MT2 Prod Temp", "Timestep")
create_output(model, "PythonPlugin:OutputVariable", "lt1_t_food", "LT1 Prod Temp", "Timestep")
create_output(model, "PythonPlugin:OutputVariable", "lt2_t_food", "LT2 Prod Temp", "Timestep")
create_output(model, "Zone Air Temperature", "Zn1", "Zone Temp", "Timestep")
create_output(model, "Zone Air Relative Humidity", "Zn1", "Zone RH", "Timestep")
create_output(model, "Refrigeration Case Evaporator Fan Electricity Rate", "MT1", "Case Fan Power", "Timestep")
create_output(model, "Refrigeration Case Evaporator Fan Electricity Rate", "MT2", "Case Fan Power", "Timestep")
create_output(model, "Refrigeration Case Evaporator Fan Electricity Rate", "LT1", "Case Fan Power", "Timestep")
create_output(model, "Refrigeration Case Evaporator Fan Electricity Rate", "LT2", "Case Fan Power", "Timestep")
create_output(model, "Refrigeration Case Lighting Electricity Rate", "MT1", "Case Light Power", "Timestep")
create_output(model, "Refrigeration Case Lighting Electricity Rate", "MT2", "Case Light Power", "Timestep")
create_output(model, "Refrigeration Case Lighting Electricity Rate", "LT1", "Case Light Power", "Timestep")
create_output(model, "Refrigeration Case Lighting Electricity Rate", "LT2", "Case Light Power", "Timestep")
create_output(model, "Refrigeration Case Anti Sweat Electricity Rate", "LT2", "Case Anti Sweat Power", "Timestep")
create_output(model, "Refrigeration Case Defrost Electricity Rate", "LT1", "Case Defrost Power", "Timestep")
create_output(model, "Refrigeration Case Defrost Electricity Rate", "LT2", "Case Defrost Power", "Timestep")
create_output(model, "Refrigeration Compressor Electricity Rate", "MT Comp 1", "Case Compressor Power", "Timestep")
create_output(model, "Refrigeration Compressor Electricity Rate", "MT Comp 2", "Case Compressor Power", "Timestep")
create_output(model, "Refrigeration Compressor Electricity Rate", "LT Comp 1", "Case Compressor Power", "Timestep")
create_output(model, "Refrigeration Compressor Electricity Rate", "LT Comp 2", "Case Compressor Power", "Timestep")
create_output(model, "Fan Electricity Rate", "RTU Fan", "HVAC Fan Power", "Timestep")
create_output(model, "Heating Coil Electricity Rate", "RTU Reheat Coil", "HVAC Heating Power", "Timestep")
create_output(model, "Cooling Coil Electricity Rate", "RTU Cool Coil", "HVAC Cooling Power", "Timestep")

# other OutputVariables might be custom python defined output variables,
# you should still be able to request them here, and as long as exportToBCVTB is true they will be available via Alfalfa

return true
end
end

# register the measure to be used by the application
AlfalfaVariables.new.registerWithApplication
54 changes: 54 additions & 0 deletions workflow/base_files/measures/alfalfa_vars/measure.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0"?>
<measure>
<schema_version>3.0</schema_version>
<name>alfalfa_variables</name>
<uid>86d51823-68a5-478a-b60b-60891c3c9b5f</uid>
<version_id>5c94ef46-d8e9-4ae9-864e-d884aba51509</version_id>
<version_modified>20201216T214230Z</version_modified>
<xml_checksum>356BE47F</xml_checksum>
<class_name>AlfalfaVariables</class_name>
<display_name>AlfalfaVariables</display_name>
<description>Add custom variables for Alfalfa</description>
<modeler_description>Add EMS global variables required by Alfalfa</modeler_description>
<arguments />
<outputs />
<provenances />
<tags>
<tag>HVAC.HVAC Controls</tag>
</tags>
<attributes>
<attribute>
<name>Measure Type</name>
<value>ModelMeasure</value>
<datatype>string</datatype>
</attribute>
<attribute>
<name>Intended Software Tool</name>
<value>Apply Measure Now</value>
<datatype>string</datatype>
</attribute>
<attribute>
<name>Intended Software Tool</name>
<value>OpenStudio Application</value>
<datatype>string</datatype>
</attribute>
<attribute>
<name>Intended Software Tool</name>
<value>Parametric Analysis Tool</value>
<datatype>string</datatype>
</attribute>
</attributes>
<files>
<file>
<version>
<software_program>OpenStudio</software_program>
<identifier>3.1.0</identifier>
<min_compatible>3.1.0</min_compatible>
</version>
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>A9E1EEF2</checksum>
</file>
</files>
</measure>
20 changes: 20 additions & 0 deletions workflow/base_files/workflow.osw
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"seed_file": "",
"weather_file": "",
"measure_paths": [
"./measures"
],
"run_directory": "./run/",
"file_paths": [
"./weather/",
"./models/"
],
"steps": [
{
"measure_dir_name": "alfalfa_vars",
"name": "Alfalfa Variables",
"description": "Add custom variables for Alfalfa",
"modeler_description": "Add EMS global variables required by Alfalfa"
}
]
}
13 changes: 13 additions & 0 deletions workflow/lib/inputs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import boto3 # This is not called directly, but must be installed for Pandas to read files from S3
import pandas as pd

class Inputs:
"""Class to assign inputs for running buildstock models in Alfalfa."""

def __init__(self, year, dataset_name, upgrade, id, folder):
self.year = year
self.dataset_name = dataset_name
self.upgrade = upgrade
self.id = id
# Folder to download models
self.folder = folder
Loading
Loading