Skip to content

Commit

Permalink
Input schema (#72)
Browse files Browse the repository at this point in the history
* Fix typos.

* Add schema and change kw to be kW.

* Add schema tests.

* Update CLI and tests.

* Update reqs.

* Test.

* Fix path issue.
  • Loading branch information
lymereJ authored Oct 27, 2023
1 parent 6d6f1dd commit a7af978
Show file tree
Hide file tree
Showing 23 changed files with 409 additions and 99 deletions.
1 change: 1 addition & 0 deletions copper/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from copper.chiller import *
from copper.schema import *
from copper.constants import LOGGING_FORMAT
import sys

Expand Down
22 changes: 11 additions & 11 deletions copper/chiller.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,17 +190,17 @@ def get_ref_cond_flow_rate(self):
else:
evap_power = self.ref_cap

if self.ref_cap_unit != "kw/ton":
if self.ref_cap_unit != "kW/ton":
ref_cap = Units(value=self.ref_cap, unit=self.ref_cap_unit)
ref_cap = ref_cap.conversion(new_unit="kw/ton")
ref_cap = ref_cap.conversion(new_unit="kW/ton")
else:
ref_cap = self.ref_cap

# Convert reference efficiency if needed
if self.full_eff_unit != "kw/ton":
if self.full_eff_unit != "kW/ton":
full_eff_unit = Units(value=self.full_eff, unit=self.full_eff_unit)
full_eff = full_eff_unit.conversion(
new_unit="kw/ton"
new_unit="kW/ton"
) # full eff needs to be in kW/ton
else:
full_eff = self.full_eff
Expand Down Expand Up @@ -329,9 +329,9 @@ def get_eir_ref(self, alt):
kwpton_ref_unit = self.full_eff_unit

# Convert to kWpton if necessary
if self.full_eff_unit != "kw/ton":
if self.full_eff_unit != "kW/ton":
kwpton_ref_unit = Units(kwpton_ref, kwpton_ref_unit)
kwpton_ref = kwpton_ref_unit.conversion("kw/ton")
kwpton_ref = kwpton_ref_unit.conversion("kW/ton")

# Conversion factors
# TODO: remove these and use the unit class
Expand Down Expand Up @@ -372,7 +372,7 @@ def calc_eff_ect(self, cap_f_t, eir_f_t, eir_f_plr, eir_ref, ect, lwt, load):

return eir

def calc_rated_eff(self, eff_type, unit="kw/ton", output_report=False, alt=False):
def calc_rated_eff(self, eff_type, unit="kW/ton", output_report=False, alt=False):
"""Calculate chiller efficiency.
:param str eff_type: Chiller efficiency type, currently supported `full` (full load rating)
Expand Down Expand Up @@ -505,8 +505,8 @@ def calc_rated_eff(self, eff_type, unit="kw/ton", output_report=False, alt=False

# Stop here for full load calculations
if eff_type == "full" and idx == 0:
if unit != "kw/ton":
kwpton = Units(kwpton, "kw/ton").conversion(unit)
if unit != "kW/ton":
kwpton = Units(kwpton, "kW/ton").conversion(unit)
return kwpton

# Coefficients from AHRI Std 551/591
Expand All @@ -523,8 +523,8 @@ def calc_rated_eff(self, eff_type, unit="kw/ton", output_report=False, alt=False
return -999

# Convert IPLV to desired unit
if unit != "kw/ton":
iplv_org = Units(iplv, "kw/ton")
if unit != "kW/ton":
iplv_org = Units(iplv, "kW/ton")
iplv = iplv_org.conversion(unit)

return iplv
Expand Down
22 changes: 14 additions & 8 deletions copper/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

import click, json, inspect

# import copper.Chiller as chiller
from copper.chiller import Chiller
import copper.schema


@click.group()
Expand All @@ -23,18 +23,23 @@ def cli():
@click.argument("input_file", type=click.File("rb"), required=True)
def run(input_file):
"""Run a set of Copper instructions through a JSON input file. See 'Using Copper's command line interface in the Quickstart Guide section of the documenation for more information."""

try:
f = json.load(input_file)

# Validate input file
assert copper.Schema(f).validate() == True
except:
raise ValueError("Could not read the input file. A JSON file is expected.")
for eqp, eqp_props in f.items():
for action in f["actions"]:
eqp_props = action["equipment"]
# Make sure that the equipment is supported by Copper
assert eqp_props["eqp_type"].lower() in [
assert eqp_props["type"].lower() in [
"chiller"
], "Equipment type not currently supported by Copper."

# Get properties for equipment type
eqp_type_props = inspect.getfullargspec(eval(eqp_props["eqp_type"]).__init__)[0]
eqp_type_props = inspect.getfullargspec(eval(eqp_props["type"]).__init__)[0]

# Set the equipment properties from input file
obj_args = {}
Expand All @@ -43,12 +48,13 @@ def run(input_file):
obj_args[p] = eqp_props[p]

# Create instance of the equipment
obj = eval(eqp_props["eqp_type"])(**obj_args)
obj = eval(eqp_props["type"])(**obj_args)

# Perform actions defined in input file
if "do" in list(eqp_props.keys()):
for action in eqp_props["do"]:
getattr(obj, action)(**eqp_props["do"][action])
func = action["function_call"]["function"]
del action["function_call"]["function"]
args = action["function_call"]
getattr(obj, func)(**args)


if __name__ == "__main__":
Expand Down
10 changes: 10 additions & 0 deletions copper/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,14 @@
====================================
Holds all the constants referenced in copper.
"""

import os

LOGGING_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
ROOT_DIR = os.path.dirname(__file__)
CHILLER_SCHEMA_PATH = f"{ROOT_DIR}/../schema/copper.chiller.schema.json"
CHILLER_GENE_SCHEMA_PATH = (
f"{ROOT_DIR}/../schema/copper.chiller.generate_set_of_curves.schema.json"
)
CHILLER_ACTION_SCHEMA_PATH = f"{ROOT_DIR}/../schema/copper.chiller.action.schema.json"
SCHEMA_PATH = f"{ROOT_DIR}/../schema/copper.schema.json"
2 changes: 1 addition & 1 deletion copper/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def run_ga(self, curves, verbose=False):
restart += 1

logging.info(
"GEN: {}, IPLV: {}, KW/TON: {}".format(
"GEN: {}, IPLV: {}, kW/ton: {}".format(
gen,
round(
self.equipment.calc_rated_eff(
Expand Down
43 changes: 43 additions & 0 deletions copper/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
schema.py
====================================
Validation of the CLI input files.
"""

import json, jsonschema, logging
from copper.constants import SCHEMA_PATH
from copper.constants import CHILLER_SCHEMA_PATH
from copper.constants import CHILLER_GENE_SCHEMA_PATH
from copper.constants import CHILLER_ACTION_SCHEMA_PATH

# Load schemas
schema_chiller = json.load(open(CHILLER_SCHEMA_PATH, "r"))
schema_chiller_gene = json.load(open(CHILLER_GENE_SCHEMA_PATH, "r"))
schema_chiller_action = json.load(open(CHILLER_ACTION_SCHEMA_PATH, "r"))
schema = json.load(open(SCHEMA_PATH, "r"))

# Define schema store for the validator
schema_store = {
"copper.chiller.schema.json": schema_chiller,
"copper.chiller.generate_set_of_curves.schema.json": schema_chiller_gene,
"copper.chiller.action.schema.json": schema_chiller_action,
"copper.schema.json": schema,
}


class Schema:
def __init__(self, input):
self.input = input
self.schema = schema
self.schema_store = schema_store
self.resolver = jsonschema.RefResolver.from_schema(schema, store=schema_store)
Validator = jsonschema.validators.validator_for(schema)
self.validator = Validator(self.schema, resolver=self.resolver)

def validate(self):
try:
self.validator.validate(self.input)
return True
except:
logging.critical("Input file is not valid.")
return
8 changes: 4 additions & 4 deletions copper/units.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ def conversion(self, new_unit):
:rtype: float
"""
if new_unit == "kw/ton":
if new_unit == "kW/ton":
if self.unit == "cop":
return 12.0 / (self.value * 3.412)
elif self.unit == "kw/ton":
elif self.unit == "kW/ton":
return self.value
elif self.unit == "eer":
return 12.0 / self.value
else:
return self.value
elif new_unit == "cop":
if self.unit == "kw/ton":
if self.unit == "kW/ton":
return 12.0 / self.value / 3.412
elif self.unit == "cop":
return self.value
Expand All @@ -37,7 +37,7 @@ def conversion(self, new_unit):
else:
return self.value
elif new_unit == "eer":
if self.unit == "kw/ton":
if self.unit == "kW/ton":
return 12.0 / self.value
elif self.unit == "eer":
return self.value
Expand Down
16 changes: 8 additions & 8 deletions docs/source/Additional Examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ Most building energy modeling software use an entering condenser temperature (EC
ref_cap=100,
ref_cap_unit="ton",
full_eff=full_eff_target,
full_eff_unit="kw/ton",
full_eff_unit="kW/ton",
part_eff=part_eff_target,
part_eff_unit="kw/ton",
part_eff_unit="kW/ton",
part_eff_ref_std="ahri_550/590",
model="lct_lwt",
sim_engine="energyplus",
Expand Down Expand Up @@ -52,14 +52,14 @@ The rating conditions in AHRI Standards 550/590 and 551/591 are different. **Cop
ref_cap=100,
ref_cap_unit="ton",
full_eff=full_eff_target,
full_eff_unit="kw/ton",
full_eff_unit="kW/ton",
full_eff_alt=full_eff_target_alt,
full_eff_unit_alt="kw/ton",
full_eff_unit_alt="kW/ton",
part_eff=part_eff_target,
part_eff_unit="kw/ton",
part_eff_unit="kW/ton",
part_eff_ref_std="ahri_550/590",
part_eff_alt=part_eff_target_alt,
part_eff_unit_alt="kw/ton",
part_eff_unit_alt="kW/ton",
part_eff_ref_std_alt="ahri_551/591",
model="ect_lwt",
sim_engine="energyplus",
Expand All @@ -83,9 +83,9 @@ Because **Copper** is used to find a solution to an underdetermined system of eq
ref_cap=300,
ref_cap_unit="ton",
full_eff=0.610,
full_eff_unit="kw/ton",
full_eff_unit="kW/ton",
part_eff=0.520,
part_eff_unit="kw/ton",
part_eff_unit="kW/ton",
sim_engine="energyplus",
model="ect_lwt",
compressor_type="screw",
Expand Down
8 changes: 4 additions & 4 deletions docs/source/Quickstart Guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ Next, we define the chiller. In this example, the chiller is a 300 ton constant
ref_cap=300,
ref_cap_unit="ton",
full_eff=0.610,
full_eff_unit="kw/ton",
full_eff_unit="kW/ton",
part_eff=0.520,
part_eff_unit="kw/ton",
part_eff_unit="kW/ton",
sim_engine="energyplus",
model="ect_lwt",
compressor_type="screw",
Expand Down Expand Up @@ -106,9 +106,9 @@ First, we create the JSON input file.
"ref_cap":300,
"ref_cap_unit":"ton",
"full_eff":0.61,
"full_eff_unit":"kw/ton",
"full_eff_unit":"kW/ton",
"part_eff":0.52,
"part_eff_unit":"kw/ton",
"part_eff_unit":"kW/ton",
"sim_engine":"energyplus",
"model":"ect_lwt",
"do":{
Expand Down
Binary file modified requirements.txt
Binary file not shown.
26 changes: 26 additions & 0 deletions schema/copper.chiller.action.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"$schema": "https://json-schema.org/draft-07/schema",
"title": "Chiller functions",
"description": "Run a function for a chiller",
"definitions": {
"action": {
"type": "object",
"properties": {
"equipment": {
"description": "Chiller definition",
"$ref": "copper.chiller.schema.json#/definitions/chiller"
},
"function_call": {
"description": "Chiller-specific function call",
"oneOf": [
{
"$ref": "copper.chiller.generate_set_of_curves.schema.json#/definitions/generate_set_of_curves"
}
]
}
},
"required": ["equipment", "function_call"]
}
},
"$ref": "copper.chiller.action.schema.json#/definitions/action"
}
50 changes: 50 additions & 0 deletions schema/copper.chiller.generate_set_of_curves.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"$schema": "https://json-schema.org/draft-07/schema",
"title": "Generate set of curves",
"description": "Generate set of curves for chillers",
"definitions": {
"generate_set_of_curves": {
"type": "object",
"properties": {
"function": {
"description": "Function to be called",
"type": "string",
"enum": ["generate_set_of_curves"],
"minLength": 1
},
"vars": {
"description": "Curve modifier that will be modified to target full and part load efficiencies",
"type": "array",
"items": {
"type": "string",
"enum": ["eir-f-t", "cap-f-t", "eir-f-plr"]
}
},
"method": {
"description": "Aggregation method used to generate the typical curve",
"type": "string",
"enum": ["nearest_neighbor", "average", "median"]
},
"tol": {
"description": "Tolerance for the optimization process",
"type": "number"
},
"export_path": {
"description": "Path to export the generated performance curves",
"type": "string"
},
"export_format": {
"description": "File format of the generated performance curves",
"type": "string",
"enum": ["idf", "json", "csv"]
},
"export_name": {
"description": "Name of the generated set of performance curves",
"type": "string",
"minLength": 1
}
}
}
},
"$ref": "copper.chiller.generate_set_of_curves.schema.json#/definitions/generate_set_of_curves"
}
Loading

0 comments on commit a7af978

Please sign in to comment.