From 0b8aa989f7c6018eb5a094061dda83e677b8b2bf Mon Sep 17 00:00:00 2001 From: taoning Date: Tue, 20 Aug 2024 15:02:46 -0700 Subject: [PATCH] fix(eplus): fix error when cfs is None --- frads/eplus.py | 112 ++++++++++++++++--------------------------------- 1 file changed, 37 insertions(+), 75 deletions(-) diff --git a/frads/eplus.py b/frads/eplus.py index 5e91930..0485a41 100644 --- a/frads/eplus.py +++ b/frads/eplus.py @@ -2,23 +2,21 @@ Class and functions for accessing EnergyPlus Python API """ +import ast import datetime -import json -from pathlib import Path -from typing import Dict, List, Optional, Callable, Union import inspect -import ast +import json import tempfile +from pathlib import Path +from typing import Callable, Dict, List, Optional, Union +import numpy as np from epmodel import epmodel as epm +from pyenergyplus.api import EnergyPlusAPI + from frads.ep2rad import epmodel_to_radmodel -from frads.methods import ( - WorkflowConfig, - ThreePhaseMethod, -) from frads.eplus_model import EnergyPlusModel -import numpy as np -from pyenergyplus.api import EnergyPlusAPI +from frads.methods import ThreePhaseMethod, WorkflowConfig def ep_datetime_parser(inp: str): @@ -31,9 +29,9 @@ def ep_datetime_parser(inp: str): month, day = [int(i) for i in date.split("/")] hr, mi, sc = [int(i) for i in time.split(":")] if hr == 24 and mi == 0 and sc == 0: - return datetime.datetime( - 1900, month, day, 0, mi, sc - ) + datetime.timedelta(days=1) + return datetime.datetime(1900, month, day, 0, mi, sc) + datetime.timedelta( + days=1 + ) else: return datetime.datetime(1900, month, day, hr, mi, sc) @@ -86,9 +84,7 @@ def __init__( k: WorkflowConfig.from_dict(v) for k, v in self.rmodels.items() } # Default to Three-Phase Method - self.rworkflows = { - k: ThreePhaseMethod(v) for k, v in self.rconfigs.items() - } + self.rworkflows = {k: ThreePhaseMethod(v) for k, v in self.rconfigs.items()} for v in self.rworkflows.values(): v.config.settings.save_matrices = True v.generate_matrices(view_matrices=False) @@ -101,9 +97,7 @@ def __init__( self.construction_handles = {} self.construction_names = {} self.enable_radiance = enable_radiance - self.api.runtime.callback_begin_new_environment( - self.state, self._get_handles() - ) + self.api.runtime.callback_begin_new_environment(self.state, self._get_handles()) self.actuators = [] self._get_list_of_actuators() @@ -119,9 +113,7 @@ def __exit__(self, exc_type, exc_value, exc_tb): def _actuator_func(self, state): if len(self.actuators) == 0: api_data: List[str] = ( - self.api.api.listAllAPIDataCSV(state) - .decode("utf-8") - .splitlines() + self.api.api.listAllAPIDataCSV(state).decode("utf-8").splitlines() ) for line in api_data: if line.startswith("Actuator"): @@ -140,18 +132,14 @@ def _get_list_of_actuators(self): with tempfile.TemporaryDirectory() as tmpdir: inp = Path(tmpdir) / "in.json" with open(inp, "w") as wtr: - wtr.write( - self.model.model_dump_json(by_alias=True, exclude_none=True) - ) + wtr.write(self.model.model_dump_json(by_alias=True, exclude_none=True)) if self.epw is not None: self.api.runtime.run_energyplus( actuator_state, ["-p", "actuator", "-w", self.epw, str(inp)] ) elif self.model.sizing_period_design_day is not None: - self.api.runtime.run_energyplus( - actuator_state, ["-D", str(inp)] - ) + self.api.runtime.run_energyplus(actuator_state, ["-D", str(inp)]) else: raise ValueError( "Specify weather file in EnergyPlusSetup " @@ -177,9 +165,7 @@ def actuate(self, component_type: str, name: str, key: str, value: float): Examples: >>> epsetup.actuate("Weather Data", "Outdoor Dew Point", "Environment", 10) """ - if ( - key not in self.actuator_handles - ): # check if key exists in actuator handles + if key not in self.actuator_handles: # check if key exists in actuator handles self.actuator_handles[key] = {} if ( name not in self.actuator_handles[key] @@ -335,9 +321,7 @@ def callback_function(state): for key in self.variable_handles: try: for name in self.variable_handles[key]: - handle = self.api.exchange.get_variable_handle( - state, name, key - ) + handle = self.api.exchange.get_variable_handle(state, name, key) if handle == -1: raise ValueError( "Variable handle not found: " @@ -345,35 +329,26 @@ def callback_function(state): ) self.variable_handles[key][name] = handle except TypeError: - print( - "No variables requested for", self.variable_handles, key - ) + print("No variables requested for", self.variable_handles, key) if self.model.construction_complex_fenestration_state is not None: for cfs in self.model.construction_complex_fenestration_state: - handle = self.api.api.getConstructionHandle( - state, cfs.encode() - ) + handle = self.api.api.getConstructionHandle(state, cfs.encode()) if handle == -1: raise ValueError( - "Construction handle not found: " - f"Construction = {cfs}" + "Construction handle not found: " f"Construction = {cfs}" ) self.construction_handles[cfs] = handle self.construction_names[handle] = cfs - for w in self.model.fenestration_surface_detailed: - if ( - self.model.fenestration_surface_detailed[ - w - ].construction_name - in self.model.construction_complex_fenestration_state - ): - self.actuate_cfs_state( - w, - self.model.fenestration_surface_detailed[ - w - ].construction_name, - ) + for wname, window in self.model.fenestration_surface_detailed.items(): + if ( + window.construction_name + in self.model.construction_complex_fenestration_state + ): + self.actuate_cfs_state( + wname, + window.construction_name, + ) return callback_function @@ -470,14 +445,10 @@ def run( } with open(f"{output_prefix}.json", "w") as wtr: - wtr.write( - self.model.model_dump_json(by_alias=True, exclude_none=True) - ) + wtr.write(self.model.model_dump_json(by_alias=True, exclude_none=True)) self.api.runtime.set_console_output_status(self.state, not silent) - self.api.runtime.run_energyplus( - self.state, [*opt, f"{output_prefix}.json"] - ) + self.api.runtime.run_energyplus(self.state, [*opt, f"{output_prefix}.json"]) def set_callback(self, method_name: str, func: Callable): """Set callback function for EnergyPlus runtime API. @@ -504,9 +475,7 @@ def set_callback(self, method_name: str, func: Callable): # method(self.state, partial(func, self)) method(self.state, func) - def _request_variables_from_callback( - self, callable_nodes: List[ast.Call] - ) -> None: + def _request_variables_from_callback(self, callable_nodes: List[ast.Call]) -> None: key_value_pairs = set() for node in callable_nodes: key_value_dict = {} @@ -544,20 +513,15 @@ def _request_variables_from_callback( key="Environment", ) - def _check_actuators_from_callback( - self, callable_nodes: List[ast.Call] - ) -> None: + def _check_actuators_from_callback(self, callable_nodes: List[ast.Call]) -> None: def get_zone_from_pair_arg(node: ast.Call) -> str: if len(node.args) == 2: zone = ast.literal_eval(node.args[0]) elif len(node.keywords) == 2: key_value_dict = { - node.keywords[i].arg: node.keywords[i].value.value - for i in range(2) + node.keywords[i].arg: node.keywords[i].value.value for i in range(2) } - zone = key_value_dict.get( - "zone", key_value_dict.get("surface", None) - ) + zone = key_value_dict.get("zone", key_value_dict.get("surface", None)) else: raise ValueError(f"Invalid number of arguments in {node}.") return zone @@ -566,9 +530,7 @@ def get_zone_from_pair_arg(node: ast.Call) -> str: key_value = None if node.func.attr == "actuate": if len(node.args) == 4: - key_value = [ - ast.literal_eval(node.args[i]) for i in range(3) - ] + key_value = [ast.literal_eval(node.args[i]) for i in range(3)] elif len(node.keywords) == 4: key_value_dict = { node.keywords[i].arg: node.keywords[i].value.value