diff --git a/.github/workflows/sample_constrain_run.py b/.github/workflows/sample_constrain_run.py index 19cd3303..9038cffd 100644 --- a/.github/workflows/sample_constrain_run.py +++ b/.github/workflows/sample_constrain_run.py @@ -31,7 +31,7 @@ response = requests.get(url) data = json.loads(response.content) - # 2- Change data path + # 2 - Change data path data["states"]["load data"]["Parameters"]["data_path"] = str( Path(__file__).parent.parent.parent / "constrain/demo/G36_demo/data/G36_Modelica_Jan.csv" diff --git a/README.md b/README.md index bafe3508..f194ec56 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,12 @@ While the development of ConStrain was motivated by use cases with building ener - Authority having jurisdiction (AHJ) – achieve better compliance rates for control provisions in code. - Mechanical engineer/energy modeler – ensure that chosen systems and their controls will comply with code. - Energy code/control guideline developer – identify ambiguity in code languages. -- BEM software developer – identify control related issues in simulation engine. +- BEM users and software developer – identify control related issues in simulation engine. # Current Version of _ConStrain_? The current version of ConStrain includes the framework implementation, a preliminary development and implementation of the verification library (based on ASHRAE 90.1-2016 control related requirement), and the test cases of verification algorithms using prototype building models. The current list of implemented verification algorithms includes supply air temperature control, economizer high limit, integrated economizer control, zone temperature control (dead band), zone temperature control (setback), hot water temperature reset, chilled water temperature reset, etc. -A newly released API helps users to use ConStrain more easily. An API workflow demo is provided at `demo/api_demo` and `test/api/test_workflow.py` - See the Publications section for more information and example of uses of the framework. ## Get Started diff --git a/constrain/api/brick_compliance.py b/constrain/api/brick_compliance.py index 7454da05..d15dd7e1 100644 --- a/constrain/api/brick_compliance.py +++ b/constrain/api/brick_compliance.py @@ -1,3 +1,9 @@ +""" +brick_compliance.py +==================================== +Brick Compliance API +""" + import ast import copy import json diff --git a/constrain/api/reporting.py b/constrain/api/reporting.py index bfc3e311..0dc9c8fa 100644 --- a/constrain/api/reporting.py +++ b/constrain/api/reporting.py @@ -23,7 +23,7 @@ def __init__( ) -> None: """ Args: - verification_json (str, optional): Path to the result json files after verifications to be loaded for reporting. It can be one JSON file or wildcard for multiple JSON files (e.g., *_md.json). + verification_json (str, optional): Path to the result json files after verifications to be loaded for reporting. It can be one JSON file or wildcard for multiple JSON files (e.g., \*_md.json). result_md_name (str, optional): Name of the report summary markdown to be saved. All md reports will be created in the same directory as the verification result json files. report_format (str, optional): File format to be output. For now, only `markdown` format is available. More formats (e.g., html, pdf, csv, etc.) will be added in future releases. """ diff --git a/constrain/api/verification.py b/constrain/api/verification.py index e2c9878e..98b69115 100644 --- a/constrain/api/verification.py +++ b/constrain/api/verification.py @@ -72,7 +72,7 @@ def configure( time_series_csv_export_name_prefix (str, optional): CSV file name prefix for saving a complete data csv file with verification result flags. Defaults to None, which will not save any time series data archives. lib_items_path (str, optional): User provided verification item json path (include name of the file with extension). lib_classes_py_file (str, optional): User provided verification item python classes file. - plot_option (str, optional): Type of plots to include. It should either be all-compact, all-expand, day-compact, or day-expand. It can also be None, which will plot all types. Default to None. + plot_option (str, optional): Type of plots to include. It should either be all-compact (all variables are plotted into one single plot), all-expand (individual plots for each variables), day-compact (all variables are plotted into one single plot and only cover one day), or day-expand (individual plots for each variables and only cover one day). It can also be None, which will plot all types. Default to None. fig_size (tuple, optional): Tuple of integers (length, height) describing the size of the figure to plot. Defaults to (6.4, 4.8). num_threads (int, optional): Number of threads to run verifications in parallel. Defaults to 1. preprocessed_data (pd.DataFrame, optional): Pre-processed data stored in the data frame. Default to None. diff --git a/constrain/checklib.py b/constrain/checklib.py index be8424fa..0827e7bd 100644 --- a/constrain/checklib.py +++ b/constrain/checklib.py @@ -1,4 +1,6 @@ """ +checklib.py +==================================== This file containing the high level interface for implementing verification item classes in library.py """ diff --git a/constrain/demo/G36_demo/data/G36_library_verification_cases.json b/constrain/demo/G36_demo/data/G36_library_verification_cases.json index 65d320e4..787cff88 100644 --- a/constrain/demo/G36_demo/data/G36_library_verification_cases.json +++ b/constrain/demo/G36_demo/data/G36_library_verification_cases.json @@ -45,7 +45,8 @@ "position_damper_air_outdoor_min": "min_oa_p", "position_damper_air_outdoor_max": "max_oa_p", "flag_economizer_limit": "economizer_high_limit_reached" - } + }, + "parameters": {} }, "verification_class": "G36OutdoorAirDamperPositionForReliefDamperOrFan" }, diff --git a/constrain/schema/library.json b/constrain/schema/library.json index 6633e279..d2d1f43f 100644 --- a/constrain/schema/library.json +++ b/constrain/schema/library.json @@ -534,11 +534,11 @@ "mode_operation": "System operation mode", "temperature_air_outdoor": "Outdoor air temperature", "temperature_air_supply_max": "Maximum supply air temperature setpoint based on requests", - "temperature_air_outdoor_supply_max": "Maximum outdoor air temperature for linear SAT reset", + "temperature_air_outdoor_supply_max": "Maximum outdoor air temperature for linear SAT reset", "temperature_air_outdoor_supply_min": "Minimum outdoor air temperature for linear SAT reset", "temperature_air_supply_setpoint_cool_min": "Minimum cooling supply air temperature setpoint", "temperature_air_supply_setpoint_cool_max": "Maximum cooling supply air temperature setpoint", - "temperature_air_supply_setpoint": "Supply air temperature setpoint" + "temperature_air_supply_setpoint": "Supply air temperature setpoint" }, "description_verification_type": "procedure-based", "assertions_type": "pass", @@ -776,7 +776,7 @@ "output_coil_cooling": "AHU cooling coil heat transfer rate", "position_damper_air_return_max": "Maximum return air damper position", "position_damper_air_return": "Return air damper position", - "position_damper_air_relief": "Relief air damper position" + "position_damper_air_relief": "Relief air damper position" }, "description_verification_type": "procedure-based", "assertions_type": "pass", @@ -1556,7 +1556,7 @@ "end" ] }, - "VAVMinimumTurndownDuringReheatPressureReset": { + "VAVMinimumTurndownDuringReheatPressureReset": { "library_item_id": 69, "description_brief": "When a VAV box is in reheat mode, the ratio of VAV airflow rate to VAV max airflow rate must not be greater than the min design turndown ratio and the pressure setpoint must remain the same", "description_index": [ @@ -1577,11 +1577,11 @@ " Untested", " if flow_volumetric_air_max > 0.0 and flow_volumetric_air_vav / flow_volumetric_air_max > ratio_turndown_min:", " if pressure_static_setpoint_prev is None:", - " Untested", - " elif abs(pressure_static_setpoint - pressure_static_setpoint_prev) > 0:", - " Untested", - " else:", - " fail", + " Untested", + " elif abs(pressure_static_setpoint - pressure_static_setpoint_prev) > 0:", + " Untested", + " else:", + " fail", " else:", " pass", "else: ", @@ -1613,11 +1613,11 @@ " pass", " else: ", " fail", - " end", + " end", "end" ] }, - "ChilledWaterPlantSizingWholePlant": { + "ChilledWaterPlantSizingWholePlant": { "library_item_id": 71, "description_brief": "", "description_index": [ @@ -1625,7 +1625,7 @@ ], "description_datapoints": { "load_plant_water_chilled": "Chilled water plant load", - "temperature_air_outdoor": "Outdoor air temperature", + "temperature_air_outdoor": "Outdoor air temperature", "capacity_nominal_plant_water_chilled": "Nominal capacity of the chilled water plant", "temperature_drybulb_day_design_cooling": "Cooling design day drybulb temperature", "factor_oversizing": "Oversizing factor" @@ -1642,7 +1642,7 @@ " return 'Untested'" ] }, - "ChilledWaterPlantSizingMultipleChillers": { + "ChilledWaterPlantSizingMultipleChillers": { "library_item_id": 72, "description_brief": "", "description_index": [ @@ -1650,7 +1650,7 @@ ], "description_datapoints": { "status_chiller": "Chiller Status", - "load_plant_water_chilled": "Chilled water plant load" + "load_plant_water_chilled": "Chilled water plant load" }, "description_verification_type": "procedure-based", "assertions_type": "pass", @@ -1679,7 +1679,7 @@ "end" ] }, - "ChilledWaterPlantSizingChillerMaxLoading": { + "ChilledWaterPlantSizingChillerMaxLoading": { "library_item_id": 73, "description_brief": "", "description_index": [ @@ -1701,7 +1701,7 @@ " end" ] }, - "ChilledWaterPlantSizingChillerShortCycling": { + "ChilledWaterPlantSizingChillerShortCycling": { "library_item_id": 74, "description_brief": "", "description_index": [ @@ -1709,7 +1709,7 @@ ], "description_datapoints": { "status_chiller": "Chiller status", - "cycles_number_maximum": "Maximum allowed number of cycles per hour" + "cycles_number_maximum": "Maximum allowed number of cycles per hour" }, "description_verification_type": "rule-based", "assertions_type": "pass", diff --git a/design/api_design.md b/design/api_design.md deleted file mode 100644 index f8c2e5a8..00000000 --- a/design/api_design.md +++ /dev/null @@ -1,870 +0,0 @@ -# ANIMATE APIs design - -Authors: Xuechen Lei, Jeremy Lerond, Yun Joon Jung - -Date Modified: 01/21/2023 - ---- - -## Intro - -The ANIMATE application programming interfaces (APIs) are a collection of functions for performing common tasks with ANIMATE. These APIs are Python methods implementations with stable and well-documented interface. These methods are organized into different API categories (as Python classes) based on their functionalities and subjects. - -## Verification Library API - -Use this API to manage the verification items library - -`class VerificationLibrary` - ---- - -- [x] `__init__(`_lib_path: str_`)` - Instantiate a verification library class object and load specified library items as `self.lib_items`. - - - **Parameters** - - **lib_path**: path to the verification library file or folder. If the path ends with `*.json`, then library items defined in the json file are loaded. If the path points to a directory, then library items in all jsons in this directory and its subdirectories are loaded. Library item need to have unique name defined in the json files and python files. - ---- - -- [x] `get_library_item(`_item_`)` - Get the json definition and meta information of a specific library item. - - - **Parameters** - - **items**: str. Verification item name to get. - - **Returns** `Dict` with four specific keys: - - `library_item_name`: unique str name of the library item. - - `library_json`: library item json definition in the library json file. - - `library_json_path`: path of the library json file that contains this library item. - - `library_python_path`: path of the python file that contains the python implementation of this library item. - ---- - -- [x] `get_library_items(`_items=[]_`)` - Get the json definition and meta information of a list of specific library items. - - - **Parameters** - - **items**: list of str, default []. Library items to get. By default, get all library items loaded at instantiation. - - **Returns** list of `Dict` with four specific keys: - - `library_item_name`: unique str name of the library item. - - `library_json`: library item json definition in the library json file. - - `library_json_path`: path of the library json file that contains this library item. - - `library_python_path`: path of the python file that contains the python implementation of this library item. - ---- - -- `summarize_library(`_items=[]_`)` - Summarize information of a list of library items. - - - **Parameters** - - **items**: list of str, default []. Library items to summarize. By default, summarize all library items loaded at instantiation. - - **Returns**: `Dict` that contains summary information of library items. - ---- - - - -- [x] `validate_library(`_items_`)` - Check the validity of library items definition. This validity check includes checking the completeness of json specification (against library json schema) and Python verification class definition (against library class interface) and the match between the json and python implementation. - - - **Parameters** - - **items**: list of str. Library items to validate. `items` must be filled with valid verification item(s). If not, an error occurs. - - **Returns**: `pandas.DataFrame` that contains validity information of library items. - ---- - -- [x] `get_applicable_library_items_by_datapoints(`_datapoints_`)` - Based on provided datapoints lists, identify potentially applicable library items from all loaded items. Use this function with caution as it 1) requires aligned data points naming across all library items; 2) does not check the topological relationships between datapoints. - - - **Parameters** - - **datapoints**: list of str datapoints names. - - **Returns**: `Dict` with keys being the library item names and values being the required datapoints for the corresponding keys. - ---- - -- [x] `get_required_datapoints_by_library_items(`_datapoints=[]_`)` - Summarize datapoints that need to be used to support specified library items. Use this function with caution as it 1) requires aligned data points naming across all library items; 2) does not check the topological relationships between datapoints. - - - **Parameters** - - **datapoints**: list of str, default []. Library items to summarize datapoints from. By default, summarize all library items loaded at instantiation. - - **Returns**: `Dict` with keys being the datapoint name and values being a sub `Dict` with the following keys: - - `number_of_items_using_this_datapoint`: int, number of library items that use this datapoint. - - `library_items_list`: List, of library item names that use this datapoint. - -**note for consistent naming**: - -- manage a static mapping of standardized variable names and descriptions -- validate the point name definition of library items against these mapping when validating library items - ---- - -## Data Processing API - -### Data Processing API documentation - -This API loads datasets and manipulate data before feeding it to the verification process. - -`class DataProcessing` - -- [x] `__init__(`_data_path: str_, data_source: str, timestamp_column_name: str`)` - - Class object initialization. - - - **parameters**: - - **data_path**: Path to the data (CSV format) to be loaded for processing. Data will be stored in a `pandas.DataFrame()` object. - - **data_source**: Data source name. Use `EnergyPlus` or `Other`. - - **timestamp_column_name**: Name of the column header that contains the time series timestamps. - - **Returns**: class object with `self.data` loaded with a `pandas.DataFrame`. - -- [x] `slice(`_start_time: datetime object, end_time: datetime object_, inplace=False`)` - - Discard any data in `self.data` before or after _start_time_ and _end_time_ - - - **parameters**: - - _start_time_: `datetime.date()` object that represents the first cut-off date to slice the data. - - _end_time_: `datetime.date()` object that represents the second cut-off date to slice the data. - - _inplace_: bool, whether to do inplace modification of the data. By default, False. - - **return**: `pandas.DataFrame()` that only contain a slice of the original `self.data` - -- [x] `add_parameter(`_name: str, value: float_, inplace=False`)` - - Add a parameter to `self.data`. The parameter will be added as a constant value for all index of `self.data` - - - **parameters**: - - _name_: name of the parameter to add - - _value_: value of the parameter - -- [x] `concatenate(`\*datasets: list(pandas.DataFrame), axis = None, inplace=False`)` - - Concatenate datasets with `self.data` - - - **parameters**: - - _datasets_: list of datasets to concatenate with `self.data` - - axis: 1: concatenate vertical (timestamp / row); 0: concatenate horizontally (datapoint / column). - - _inplace_: bool, whether to do inplace modification of the data. By default, False. - - when 1: check if all datasets have same columns, if not, break; - - when 0: check if all datasets have same datetime index, if not, break. - - **return**: `pandas.DataFrame` that contains the concatenated datasets - -- [x] `apply_function(`variable_names: list(str), new_var_name: str, function_to_apply: str_, inplace=False`)` - - Apply an aggregation function to a list of variables from the dataset - - - **parameters**: - - _variable_names_: list of variables from `self.data` to be used for the aggregation function - - _new_variable_name_: name of the new variable that will contain the aggregated data - - _function_to_apply_: one of the following aggregate function 'sum', 'max', 'min', or 'average' - - _inplace_: bool, whether to do inplace modification of the data. By default, False. - - **return**: `pandas.DataFrame` containing all existing and a newly computed column. - -- [x] `check()` - - Perform a sanity check on the data. - - - **return**: dict showing the following information: - - Number of missing values for each variables - - Outliers for each variable - -**for data sanity check, once we link the data with datapoint type through verification case, we can check data validity against different rules of different data types. e.g. sat should not be < -30** - -- [x] `summary()` - - Provide a summary of the dataset - - - **return**: dict showing the following information - - Number of data points - - Resolution - - For each variables - - Minimum - - Maximum - - Mean - - Standard deviation - -- [x] `plot(`_variable_names: list(str), kind= str_`)` - - Create plots of timesteries data, or scatter plot between two variables - - - **parameters**: - - _variable_names_: list of variables from `self.data` to be plotted - - _kind_: 'timeseries', or 'scatter'; If 'timeseries' is used, all variable names provided in `variable_names` will be plotted against the index timestamp from `self.data`; If 'scatter' is used, the first variables provided in the list will be used as the x-axis, the other will be on the y-axis - - **return**: `matplotlib.axes.Axes` - -- [x] `downsample(`_rule: str_, inplace=False`)` - - Downsample `self.data` according to a user provided rule - - - **parameters**: - - _frew_: follows the same convention as [pandas.DataFrame.resample](https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#dateoffset-objects) - - _inplace_: bool, whether to do inplace modification of the data. By default, False. - - **return**: `pandas.DataFrame` that contains the downsampled data - -- [x] `fill_missing_values(`\*method: str, variable_names: list, inplace=False`)` - - Fill missing values (NaN) in `self.data` following a user specified method - - - **parameters**: - - _method_: 'linear', 'pad' as described [here](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.interpolate.html) - - _variable_names_: list of variable names used for interpolation of missing values - - _inplace_: bool, whether to do inplace modification of the data. By default, False. - - **return**: `pandas.DataFrame` containing all existing and a newly computed column. - -- `check_for_verif(`_verification_case_`)` - - Checks that all variables necessary for a specific verification item are present - - - **parameters**: - - _verification_case_: verification case object generated by the verification case API - - **return**: dict that includes the following keys: `result` which is a bool, and `notes` which provides the list of missing variables from `self.data` to correctly perform the verification - -**maybe create duals in Verification Case API / Verification API** - -### Data Processing API Examples - -```python -import animate as an -from datetime import date - -# Load the data -dp = an.DataProcessing("./data.csv") - -# Slice the data -dp.data = dp.slice(start_time=datetime.date(2007, 12, 5), end_time=datetime.date(2007, 12, 31)) - -# Add a parameter -dp.add_parameter(name="test", value="3.412") - -# Concatenate data -dp_n = an.DataProcessing("./data2.csv") -dp.data = dp.concatenate(datasets=[dp_n]) - -# Verficication of the data -dp.check() -dp.summary() - -# Visualization of the data -# 1 - Timeseries plot -dp.plot(variable_names=["Zone 1 Temp", "Zone 2 Temp"]) - -# 2 - Scatter plot -dp.plot(variable_names=["Outdoor Air Temp", "Mixed Air Temp"]) - -# Interpolate missing data -dp.interpolate(method='linear', variable_names=['Outdoor Air Temperature']) - -# Downsampling -dp.downsampling(rule='1H') - -# Check data for verification case -case_1 = an.VerificationCase("./verification_case_1.json") # <- this API is not documented here -dp.check_for_verif(verification_case=case_1) - -``` - -## Verification Case API - -### Verification Case API documentation - -`class VerificationCase` - -- [x] `__init__('_cases: Dict_, json_case_path: str')` - - Instantiate a verification case class object and load verification case(s) in `self.case_suite` as a Dict. keys are automatically generated unique id of cases, and values are the fully defined verification case Dict. The `cases` and `json_case_path` arguments must be valid. If one argument is invalid, the class is terminated with an error message regardless of the other arguments validity. - - - **Parameter** - -_cases_: (optional) A list of Dict. dictionary that includes verification case(s). - -_json_case_path_: (optional) str. path to the verification case file. If the path ends with `*.json`, then the items in the JSON file are loaded. If the path points to a directory, then verification case item JSON files are loaded. - -- [x] `load_verification_cases_from_json(`_json_case_path: str_`)` - - Add verification cases from specified json file into `self.case_suite` - - - **Parameter** - - _json_case_path_: str, path to the json file containing fully defined verification cases. - - **Returns**: List, unique ids of verification cases loaded in `self.case_suite` - -- `load_verification_case_from_dict(`_case: Dict_`)` - - Add one verification case defined as a Dict into `self.case_suite` - - - **Parameter** - - _case_: Dict, fully defined verification case in `Dict` format - - **Returns**: unique id of the case stored in self.case_suite[unique_id] - -- `load_verification_cases_from_list(`_cases: List_`)` - - Add multiple verification cases into `self.case_suite` - - - **Parameter** - - _cases_: List, containing fully defined verification cases Dict. - - **Returns** unique id of the cases stored in self.case_suite[unique_id] - -- [x] `static create_verification_case_suite_from_base_case(`_base_case: dict, update_key_value: Dict_, keep_base_case=False`)` - - Create slightly different multiple verification cases by changing keys and values as specified in `update_key_value`. if `keep_base_case` is set to True, the `base_case` is added to the first element in the returned list. - - - **parameters**: - - _base_case_: Dict. base verification input information. - - _update_key_value_: Dict. the same format as the `base_case` arg, but the updating fields consist of a list of values to be populated with. - - _keep_base_case_: Bool, whether to keep the base case in returned list of verification cases. Default to False. - - **Returns** List. A list of Dict, each dict is a generated case from the base case. - -Example: - -Base case: - -```json -{ - "data_points": { - "sat": { - "variable": "ahu1_sat" - }, - "rat": { - "variable": "ahu1_rat" - } - } -} -``` - -Objective: change the value of `sat`'s `variable` key to `ahu1_sat`, `ahu2_sat`, and `ahu3_sat` accordingly. Also, change the value of the `rat`'s `variable` key to `ahu1_rat`, `ahu2_rat`, and `ahu3_rat`. - -Define update_key_value as - -```json -{ - "data_points": { - "sat": { - "variable": ["ahu1_sat", "ahu2_sat", "ahu3_sat"] - }, - "rat": { - "variable": ["ahu1_rat", "ahu2_rat", "ahu3_rat"] - } - } -} -``` -The returned list is as follows. - -i) first element in the returned list. -```json -{ - "data_points": { - "sat": { - "variable": "ahu1_sat", - }, - "rat": { - "variable": "ahu1_rat", - } - } -``` -ii) second element in the returned list. -```json -{ - "data_points": { - "sat": { - "variable": "ahu2_sat", - }, - "rat": { - "variable": "ahu2_rat", - } - } -``` -iii) third element in the returned list. -```json -{ - "data_points": { - "sat": { - "variable": "ahu3_sat", - }, - "rat": { - "variable": "ahu3_rat", - } - } -``` - -- `get_verification_case_template(`_tamplate_format: str_`)` - - return a verification case template with contents being descriptive placeholders. - - - **return**: Dictionary that has the `new_library_verification_cases.json` format - -- [x] `static validate_verification_case_structure(`_case: dict, verbose: bool=False_`)` - - Validate verification case structure (e.g., check whether `run_simulation`, `simulation_IO`, etc. exist or not). Check if required key / values pairs exist in the case. check if datatype of values are appropriate, e.g. file path is str. - - -**parameters**: - - - `_case_`: case information that will be validated. - - `_verbose_`: whether to output verbose information. Default to False. - - **return**: Bool, indicating whether the case structure is valid or not. - - - -- `static validate_verification_case_validity(`_case: dict, verbose: bool=False, run_path:str='_'`)` - - Validate the contents in the verification case. Deeper validation to things like, if the idf file path is pointing at a valid idf file. This is more advanced and optional feature. - - - **parameters**: - - `_case_`: case information that will be validated. - - `_verbose_`: whether to output verbose information. Default to False. - - `_run_path_`: str, directory path where the user intends to run the verification case from. This is used to check for validity of relative paths used in the verification case definition. By default, use current working directory. - - **return**: Bool, indicating whether the case content is valid or not (bool). - - - -- [x] `save_case_suite_to_json(`_json_path: str, case_ids=[]_`)` - - Save verification cases to a dedicated file. If the `case_ids` argument is empty, all the cases in `self.case_suite` is saved. If `case_ids` includes specific cases' hash, only the hashes in the list are saved. - - - **parameters**: - - _json_path_: str. path to the json file to save the cases. - - _case_ids_: List. Unique ids of verification cases to save. By default, save all cases in `self.case_suite`. Default to an empty list. - -- [x] `static save_verification_cases_to_json(`_json_path: str, cases: list_`) - - Save verification cases to a dedicated file. The cases list consists of verification case dicts. - - - **parameters**: - - _json_path_: str. json file path to save the cases. - - _cases_: List. List of complete verification cases Dictionary to save. - - - -### Verification Case API Examples - -```python -import animate as an - -# create verification items in suite -SAT_case = { - "id": "example_id", - "no": 1, - "run_simulation": true, - "simulation_IO": { - "idf": "../test_cases/doe_prototype_cases/ASHRAE901_Hospital_STD2019_Atlanta.idf", - "idd": "../resources/Energy+V9_0_1.idd", - "weather": "../weather/USA_GA_Atlanta-Hartsfield.Jackson.Intl.AP.722190_TMY3.epw", - "output": "eplusout.csv", - "ep_path": "C:\\EnergyPlusV9-0-1\\energyplus.exe" - }, - "expected_result": "fail", - "datapoints_source": { - "idf_output_variables": { - "T_zone": { - "subject": "PERIMETER_ZN_1", - "variable": "Zone Air Temperature", - "frequency": "TimeStep" - } - }, - "parameters": {} - }, - "verification_class": "testing_verification_class" -} - -# define VerificationCase object -verification_instance = an.VerificationCase(cases=[SAT_case], file_path=None) - -# load existing verification case -if sat_case_validity: - verification_instance.load_verification_cases_from_json("./schema/new_library_verification_cases.json") - -# create verification cases in suite -update_key_value = { -"datapoints_source": { - "idf_output_variables": { - "T_zone": { - "subject": ["PERIMETER_ZN_2", "PERIMETER_ZN_3", "PERIMETER_ZN_4"], - "variable": "Zone Air Temperature", - "frequency": "TimeStep" - } - } - } - -updated_base_cases_list = verification_instance.create_verification_case_suite_from_base_case(SAT_case, update_key_value) - -# save the `updated_base_cases_list` to json -verification_instnace.save_verification_cases_to_json("./schema/updated_base_case.json", updated_base_cases_list) - - -# save the updated cases -verification_instance.save_case_suite_to_json("./schema/new_library_verification_cases.json") - -``` - -## Verification API - -### Verification API documentation - -`class Verification` - -- [x] `__init__(`_verification: verification object_`)` - - Class initialization - - - **parameters**: - - **verification**: ANIMATE verification object - -- [x] `configure(`_output_path: str_, _plot_option: str_, _fig_size: tuple_, _num_threads: int_, _lib_path:str_`)` - - Configure verification environment - - - **parameters**: - - _output_path_: path to the output directory used to store the markdown verification summary file - - _plot_option_: 'all-compact', 'all-expand', 'day-compact', 'day-expand' - - _fig_size_: list that provides the height and width of the figures - - _num_threads_: number of thread to use to run verification in parallel - - _lib_path_: path the the verification library - -- [x] `run()` - - Run verification and generate a markdown report of the results - -### Verification API Examples - -```python -import animate as an - -# create verification items in suite -cases = [{ - "no": 1, - "run_simulation": True, - "simulation_IO": { - "idf": "./test_cases/doe_prototype_cases/ASHRAE901_OfficeMedium_STD2019_Atlanta.idf", - "idd": "./resources/Energy+V9_0_1.idd", - "weather": "./weather/USA_GA_Atlanta-Hartsfield.Jackson.Intl.AP.722190_TMY3.epw", - "output": "eplusout.csv", - "ep_path": "C:\\EnergyPlusV9-0-1\\energyplus.exe" - }, - "expected_result": "pass", - "datapoints_source": { - "idf_output_variables": { - "o": { - "subject": "BLDG_OCC_SCH_WO_SB", - "variable": "Schedule Value", - "frequency": "TimeStep" - }, - "m_oa": { - "subject": "CORE_BOTTOM VAV BOX COMPONENT", - "variable": "Zone Air Terminal Outdoor Air Volume Flow Rate", - "frequency": "TimeStep" - }, - "m_ea": { - "subject": "CORE_MID VAV BOX COMPONENT", - "variable": "Zone Air Terminal Outdoor Air Volume Flow Rate", - "frequency": "TimeStep" - }, - "eco_onoff": { - "subject": "PACU_VAV_BOT", - "variable": "Air System Outdoor Air Economizer Status", - "frequency": "TimeStep" - } - }, - "parameters": {} - }, - "verification_class": "AutomaticOADamperControl" - }, - { - "no": 2, - "run_simulation": True, - "simulation_IO": { - "idf": "./test_cases/doe_prototype_cases/ASHRAE901_OfficeMedium_STD2019_Atlanta.idf", - "idd": "./resources/Energy+V9_0_1.idd", - "weather": "./weather/USA_GA_Atlanta-Hartsfield.Jackson.Intl.AP.722190_TMY3.epw", - "output": "eplusout.csv", - "ep_path": "C:\\EnergyPlusV9-0-1\\energyplus.exe" - }, - "expected_result": "pass", - "datapoints_source": { - "idf_output_variables": { - "o": { - "subject": "BLDG_OCC_SCH_WO_SB", - "variable": "Schedule Value", - "frequency": "TimeStep" - }, - "m_oa": { - "subject": "CORE_MID VAV BOX COMPONENT", - "variable": "Zone Air Terminal Outdoor Air Volume Flow Rate", - "frequency": "TimeStep" - }, - "m_ea": { - "subject": "CORE_TOP VAV BOX COMPONENT", - "variable": "Zone Air Terminal Outdoor Air Volume Flow Rate", - "frequency": "TimeStep" - }, - "eco_onoff": { - "subject": "PACU_VAV_MID", - "variable": "Air System Outdoor Air Economizer Status", - "frequency": "TimeStep" - } - }, - "parameters": {} - }, - "verification_class": "AutomaticOADamperControl" - } - ] - -# Load verfication case -VC = an.VerificationCase(cases=cases) -v = an.Verification(VC) - -# Configure verification -v.configure(output_path='./results', lib_items_path='./schema/library.json', plot_option=None, num_threads = 2, fig_size= (10,2.4)) - -# Run verification -v.run() -``` - -## Reporting API - -### Reporting API documentation - -- `__init__(`_verification_md: str, result_md_path: str, report_format: str_`)` - - Class initialization - - - **parameters**: - - **verification_md**: str or List, Path to the result json files after verifications to be loaded for reporting. The string type is used when one JSON file is used or all the JSON files (e.g., *_md.json) are used. The list type is used when multiple JSON files (e.g., [file1.json, file2.json]) are used. - - **result_md_path**: str, Path to the directory where result file will be saved. - - **report_format**: str, File format to be output. For now, only `markdown` format is available. More formats (e.g., html, pdf, csv, etc.) will be added in future releases. - -- [x] `report_multiple_cases(`_item_names: List_`)` - - Report/summarize multiple verification results. - - - **Parameters** - - **case_ids**: List, of unique verification case names. If the `item_names` argument is empty, all the verification results in the `verification_json` argument are reported. - **Note, we need to assign unique verification case ids at case creation and check for verification case id uniqueness in case suite** - - -### Reporting API Examples - -``` -import animate as an - -# Initiate the Reporting class -result_md = an.Reporting("./results/*_md.json", "./results/testing.md", "markdown") - -# report multiple cases -result_md.report_multiple_cases(["SupplyAirTempReset", "AutomaticShutdown"]) -``` - -## Utilities API - -### Utilities API documentation - -`class Utilities` - -**all methods under this class are static** - -- `timestamp_alignment(`_df1: pd.DataFrame, df2: pd:DataFrame, how="inner"_`)` - - align two different dataframe data based on timestamps. We can use `pandas.DataFrame.merge` method. More explanations are shown in this [LINK](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.merge.html). - - - **parameters**: -_df1_: DataFrame that is aligned with `df2`. -_df1_: DataFrame that is aligned with `df1`. -_how_: same as the `how` arg in the merge method. {‘left’, ‘right’, ‘outer’, ‘inner’, ‘cross’}, default ‘inner’ - - **return**: DataFrame that has aligned timestamps - -- `add_DST(`_df:pd.DataFrame, year:str_`)` - - Add daylight saving time (`DST_Time`) column in `self.df` dataframe. - - - **parameters**: -_df_: DataFrame -_year_: year to be considered for DST - - **return**: df DataFrame that has DST_TIME column - -### Utilities API Examples - -```python -import animate as an - -# define Utilities object - -Utilities_instance = an.Utilities() - -# align two dataframe that have different timestamps -df1 = pd.date_range("2018-01-01", periods=36, freq="5T") # 5 min interval -df2 = pd.date_range("2018-01-01", periods=12, freq="15T") # 15 min interval - -aligned_df = Utilities_instance.timestamp_alignment(df1, df2, how="inner") - -# DST -self.df = Utilities_instance.add_DST(self.df, 2017) -``` - -## Workflow API - -The workflow API define a complete workflow of running ANIMATE verification job(s). It is designed to be an orchestration tool that coordinates the use of other categories of APIs. - -`class Workflow` - -- `static` `get_workflow_template()` - - **Returns** a `Dict` template of workflow definition with descriptions of fields to be filled. - ---- - -- `static` `list_existing_workflows(`_workflow_dir=''_`)` - List existing workflows (defined as json files) under a specific directory path. - - - **Parameters** - - **workflow_dir**: str, path to the directory containing workflow definitions (including sub directories). By default, point to the path of the example folder. - - **Returns** `Dict` with keys being workflow names and values being a `Dict` with the follwoing keys: - - `workflow_json_path`: path to the file of the workflow - - `workflow`: `Dict` of the workflow, loaded from the workflow json definition. - ---- - -- `__init__(`_workflow_path: str_`)` - Instantiate a Workflow class object and load specified workflow as a `Dict` in `self.workflow`. - - - **Parameters** - - **workflow_path**: str. path to the workflow definition json file. - - **Returns**: Workflow class object with specified workflow as a `Dict` in `self.workflow`. - ---- - -- `validate_workflow_definition(workflow)` - Validate a workflow definition. - - - **Parameters** - - **workflow**: str or Dict. If str, this is assumed to be the path to the workflow definition json file; If Dict, this is assumed to be loaded from the workflow json definition. - - **Returns** `Dict` with the following keys: - - `workflow_validity`: bool flag of the validity of the workflow definition - - `detail`: detailed info about the validity check. - ---- - -- `save(json_path)` - Save the workflow as a json file. - - **Parameters** - - **json_path**: path to the file to be saved. - ---- - -- `dryrun_workflow(verbose=False)` - **Advanced feature, optional for now.** - - **Parameters** - - `verbose`: bool. Wether to output detailed information. By default, False. - - **Returns**: bool. Whether the dry run is successful or not. - - - ---- - -- `run_workflow(verbose=False)` - - **Parameters** - - `verbose`: bool. Wether to output detailed information. By default, False. - - **Returns**: bool. Whether the run is successful or not. - ---- - -### Workflow definition schema - -```json -{{ - "workflow_name": "Name of the workflow", - "meta": { - "author": "author of the workflow", - "date": "modified date", - "version": "version number of the workflow", - "description": "Narrative description of the workflow" - }, - "third party imports": [ - "numpy", - "pandas", - "datetime" - ], - "states": [ - "Load data": { - "Type": "MethodCall", - "MethodCall": "DataProcessing", - "Parameters": { - "data": "xx.csv" - }, - "Payloads": { - "data": "$.data" - }, - "Next": "Slice data" - }, - "Slice data": { - "Type": "MethodCall", - "MethodCall": "Payloads['data'].slice", - "Parameters": { - "start_time": { - "Type": "Embedded MethodCall", - "MethodCall": "datetime.date.fromisoformat", - "Parameters": { - "fromisoformat": "20221001" - } - }, - "end_time": { - "Type": "Embedded MethodCall", - "MethodCall": "datetime.date.fromisoformat", - "Parameters": { - "fromisoformat": "20230101" - } - } - }, - "Payloads": { - "sliced_data": "$" - }, - "Next": "Data Length Check" - }, - "Data Length Check": { - "Type": "Choice", - "Choice": [ - "Variable": "len(Payloads['sliced_data']) > 1", - "BooleanEquals": "True", - "Next": "Initialize verification object" - ] - }, - "Initialize verification object": { - "Type": "MethodCall", - "MethodCall": "Verification", - "Parameters": { - "verification_cases_path": "x/yy.json" - }, - "Payloads": { - "verification": "$" - }, - "Next": "Run verification" - }, - "Run verification": { - "Type": "MethodCall", - "MethodCall": "Payloads['verification'].run", - "Parameters": {}, - "Payloads": { - "verification_md": "$.md", - "verification_flag": "$.check_bool" - }, - "Next": "Reporting" - }, - "Reporting": { - "Type": "MethodCall", - "MethodCall": "Reporting", - "Parameters": { - "verification_md": "Payloads['verification_md']", - "report_path": "x/yy.md", - "report_format": "markdown" - }, - "Payloads": { - "verification": "$" - }, - "End": "True" - } - ] -}} -``` diff --git a/design/brick_compliance_doc.md b/design/brick_compliance_doc.md deleted file mode 100644 index 288da108..00000000 --- a/design/brick_compliance_doc.md +++ /dev/null @@ -1,42 +0,0 @@ -### Brick API documentation - -`Class BrickQueryCompliance` - -- `__init__(`_brick_schema_path: str_`, `_brick_instance_path: str_`)` -Instantiate a `BrickQueryCompliance` class object and load specified brick schema and brick instance. - - **Parameters** - - **brick_schema_path**: `str` path to a brick schema to be used for query. The default location is `./resources/brick/Brick.ttl`. - - **brick_instance_path**: `str` path to a brick instance to be used for query. For now, only `.ttl` format is accepted. - - **query_statement_path**: `str` path to the query statements. The default path is `./resources/brick/query_statement.yml`. - - **datapoint_name_conversion_path**: `str` path to the datapoint conversion name saving yaml file. The default path is `./resources/brick/verification_datapoint_info.yml`. - - - **perform_reasoning**: `bool` argument whether reasoning is performed to the given instance. The default boolean value is False. - -- `validate_brick_instance()` -Validate a brick instance against the brick schema. - - **Parameters** - - **brick_schema_path_str**: `str` path to the brick schema to be used for validation. - - **Returns**: i) `bool` whether the validation passes/fails, ii) `str` message from the validation process. - -- `get_applicable_verification_lib_items(`_verification_item_lib_name_:list_`)` -Get applicable control verification library items among the `verification_item_lib_name` list from the given brick instance. - - **Parameters** - - **verification_item_lib_name**: `list` of `str` including verification item names to be tested. If empty list is provided, all the available verification library items are tested. - - **Returns**: `list` of `str` including available verification library item names from a brick instance. - -- `query_verification_case_datapoints(`_verification_item_lib_name: [str, list[str]]_`, `_energyplus_naming_assembly:bool = False_`, `_default_verification_case_values: dict = None_`)` -Query datapoints required for given verification item lib. - - **Parameters** - - **verification_item_lib_name**: `str` or `list` of `str` verification item library to be quried. If only one verification item library is quried, one `str` argument type is paased. If multiple verification item libraries are queried, `list` of `str` argument type is passed. - - **energyplus_naming_assembly**: `bool` (default: False) whether to convert the queried datapoints' name to EnergyPlus style variable name. - - **default_verification_case_values**: `dict` that has default key values. ("no", "run_simulation", "idf", "idd", "weather", "output", "ep_path", "expected_result", "parameters",) keys must exist. - - **Returns**: `list` of `dict`(s), queried results in verification case format. The return dict only includes `datapoints_source` and `verification_class` keys. - -- `query_with_customized_statement(`_custom_query_statement: str_`, `_energyplus_naming_assembly:bool = False_`, `_*verification_item_lib_name: str_`, `_default_verification_case_values: dict = None_`)` -Query datapoints with a customized query statement. When implemented, the quality check of the `query_statement` is done by checking whether the number of queried variables are the same as the required number of data points in the verification library item. - - **Parameters** - - **custom_query_statement**: `str` query statement written from users. - - **verification_item_lib_name**: `str` verification library item of the `query_statement`. - - **energyplus_naming_assembly**: `bool` (default: True) whether to convert the queried datapoints' name to EnergyPlus style variable name. - - **default_verification_case_values**: `dict` that has default key values. ("no", "run_simulation", "idf", "idd", "weather", "output", "ep_path", "expected_result", "parameters",) keys must exist. - - **Returns**: `list` of `dict` of queried result in the verification case format. `str` message from the `query_statement`'s quality check result. - \ No newline at end of file diff --git a/design/g36_lib_contents.md b/design/g36_lib_contents.md deleted file mode 100644 index fa51d546..00000000 --- a/design/g36_lib_contents.md +++ /dev/null @@ -1,29 +0,0 @@ -# ASHRAE Guideline 36 Verification Library - -## Introduction - -As our first effort to add ASHRAE Guideline 36 verification in ConStrain, a set of 17 verification items are identified and implemented based on ASHRAE Guideline 36 - 2021, multi-VAV system control sequence of operation. - -The list of verification items being added are: - -| Verification Item Name | Verification Class Name | Verification Class Location | -| ---------------------------------------------------------------------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Freeze Protection Stage 1 | G36FreezeProtectionStage1 | [constrain/library/G36FreezeProtectionStage1.py](../constrain/library/G36FreezeProtectionStage1.py) | -| Freeze Protection Stage 2 | G36FreezeProtectionStage2 | [constrain/library/G36FreezeProtectionStage2.py](../constrain/library/G36FreezeProtectionStage2.py) | -| Freeze Protection Stage 3 | G36FreezeProtectionStage3 | [constrain/library/G36FreezeProtectionStage3.py](../constrain/library/G36FreezeProtectionStage3.py) | -| Minimum Outdoor Air Control With Economizer Operation | G36MinOAwEconomizer | [constrain/library/G36MinOAwEconomizer.py](../constrain/library/G36MinOAwEconomizer.py) | -| Minimum Outdoor Air Control Without Economizer Operation | G36MinOAwoEconomizer | [constrain/library/G36MinOAwoEconomizer.py](../constrain/library/G36MinOAwoEconomizer.py) | -| Outdoor Air Damper Position For Systems with Relief Damper Or Fan | G36OutdoorAirDamperPositionForReliefDamperOrFan | [constrain/library/G36OutdoorAirDamperPositionForReliefDamperOrFan.py](../constrain/library/G36OutdoorAirDamperPositionForReliefDamperOrFan.py) | -| Outdoor Air Damper Position For Systems with Return Fan Tracking Airflow | G36OutdoorAirDamperPositionForReturnFanAirflowTracking | [constrain/library/G36OutdoorAirDamperPositionForReturnFanAirflowTracking.py](../constrain/library/G36OutdoorAirDamperPositionForReturnFanAirflowTracking.py) | -| Outdoor Air Damper Position For Systems with Return Fan Tracking Building Pressure | G36OutdoorAirDamperPositionForReturnFanDirectBuildingPressure | [constrain/library/G36OutdoorAirDamperPositionForReturnFanDirectBuildingPressure.py](../constrain/library/G36OutdoorAirDamperPositionForReturnFanDirectBuildingPressure.py) | -| Controller Output Command Change Rate Limit | G36OutputChangeRateLimit | [constrain/library/G36OutputChangeRateLimit.py](../constrain/library/G36OutputChangeRateLimit.py) | -| Relief Air Damper Position For Systems with Return Fan Tracking Airflow | G36ReliefAirDamperPositionForReturnFanAirflowTracking | [constrain/library/G36ReliefAirDamperPositionForReturnFanAirflowTracking.py](../constrain/library/G36ReliefAirDamperPositionForReturnFanAirflowTracking.py) | -| Relief Damper Status | G36ReliefDamperStatus | [constrain/library/G36ReliefDamperStatus.py](../constrain/library/G36ReliefDamperStatus.py) | -| Return Air Damper Position For Systems with Relief Damper Or Fan | G36ReturnAirDamperPositionForReliefDamperOrFan | [constrain/library/G36ReturnAirDamperPositionForReliefDamperOrFan.py](../constrain/library/G36ReturnAirDamperPositionForReliefDamperOrFan.py) | -| Return Air Damper Position For Systems with Return Fan Tracking Airflow | G36ReturnAirDamperPositionForReturnFanAirflowTracking | [constrain/library/G36ReturnAirDamperPositionForReturnFanAirflowTracking.py](../constrain/library/G36ReturnAirDamperPositionForReturnFanAirflowTracking.py) | -| Return Air Damper Position For Systems with Return Fan Tracking Building Pressure | G36ReturnAirDamperPositionForReturnFanDirectBuildingPressure | [constrain/library/G36ReturnAirDamperPositionForReturnFanDirectBuildingPressure.py](../constrain/library/G36ReturnAirDamperPositionForReturnFanDirectBuildingPressure.py) | -| Simultaneous Coil Heating and Coil Cooling | G36SimultaneousHeatingCooling | [constrain/library/G36SimultaneousHeatingCooling.py](../constrain/library/G36SimultaneousHeatingCooling.py) | -| Supply Air Temperature Setpoint | G36SupplyAirTemperatureSetpoint | [constrain/library/G36SupplyAirTemperatureSetpoint.py](../constrain/library/G36SupplyAirTemperatureSetpoint.py) | -| Supply fan Status | G36SupplyFanStatus | [constrain/library/G36SupplyFanStatus.py](../constrain/library/G36SupplyFanStatus.py) | - -Detailed description of Guideline 36 narrative interpretation and verification logic design are in comments of the corresponding verification item Python classes. \ No newline at end of file diff --git a/design/local_loop_lib_contents.md b/design/local_loop_lib_contents.md deleted file mode 100644 index ad65e7db..00000000 --- a/design/local_loop_lib_contents.md +++ /dev/null @@ -1,120 +0,0 @@ -# Local Loop Performance Verification Library Items - ----- - -## Local Loop Performance Verification - Set Point Tracking - -### Description - -This verification checks the set point tracking ability of local control loops. - -### Verification logic - -With a threshold of 5% of abs(set_point) (if the set point is 0, then the threshold is default to be 0.01), if the number of samples of which the error is larger than this threshold is beyond 5% of number of all samples, then this verification fails; Otherwise, it passes. - -### Data requirements - -- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point -- set_point: set point value - - -## Local Loop Performance Verification - Set Point Unmet Hours - -### Description - -This verification checks the set point tracking ability of local control loops. - -### Verification logic - -Instead of checking the number of samples among the whole data set for which the set points are not met, this verification checks the total accumulated time that the set points are not met within a threshold of 5% of abs(set_point) (if the set point is 0, then the threshold is default to be 0.01). - -If the accumulated time of unmet set point is beyond 5% of the whole duration the data covers, then this verification fails; otherwise, it passes. - -### Data requirements - -- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point -- set_point: set point value - -## Local Loop Performance Verification - Direct Acting Loop Actuator Maximum Saturation - -### Description - -This verification checks that a direct acting control loop would saturate its actuator to maximum when the error is consistently above the set point [^1]. - -### Verification logic - -If the sensed data values are consistently above its set point, and after a default of 1 hour, the control command is still not saturated to maximum, then the verification fails; Otherwise, it passes. - -### Data requirements - -- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point -- set_point: set point value -- cmd : control command -- cmd_max: control command range maximum value - -## Local Loop Performance Verification - Direct Acting Loop Actuator Minimum Saturation - -### Description - -This verification checks that a direct acting control loop would saturate its actuator to minimum when the error is consistently below the set point [^1]. - -### Verification logic - -If the sensed data values are consistently below its set point, and after a default of 1 hour, the control command is still not saturated to minimum, then the verification fails; Otherwise, it passes. - -### Data requirements - -- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point -- set_point: set point value -- cmd : control command -- cmd_min: control command range minimum value - -## Local Loop Performance Verification - Reverse Acting Loop Actuator Maximum Saturation - -### Description - -This verification checks that a reverse acting control loop would saturate its actuator to maximum when the error is consistently below the set point [^1]. - -### Verification logic - -If the sensed data values are consistently below its set point, and after a default of 1 hour, the control command is still not saturated to maximum, then the verification fails; Otherwise, it passes. - -### Data requirements - -- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point -- set_point: set point value -- cmd : control command -- cmd_max: control command range maximum value - -## Local Loop Performance Verification - Reverse Acting Loop Actuator Minimum Saturation - -### Description - -This verification checks that a reverse acting control loop would saturate its actuator to minimum when the error is consistently above the set point [^1]. - -### Verification logic - -If the sensed data values are consistently above its set point, and after a default of 1 hour, the control command is still not saturated to minimum, then the verification fails; Otherwise, it passes. - -### Data requirements - -- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point -- set_point: set point value -- cmd : control command -- cmd_min: control command range minimum value - - - -## Local Loop Performance Verification - Actuator Rate of Change - -### Description - -This verification checks if a local loop actuator has dramatic change of its actuating command. This verification is implemented as instructed by ASHRAE Guideline 36 2021 Section 5.1.9 in Verification Item `G36OutputChangeRateLimit`. - - - -[^1]: Lei, Xuechen, Yan Chen, Mario Bergés, and Burcu Akinci. "Formalized control logic fault definition with ontological reasoning for air handling units." Automation in Construction 129 (2021): 103781. \ No newline at end of file diff --git a/docs/source/Expand Exisiting Verifications.rst b/docs/source/Expand Exisiting Verifications.rst index ac83a2f6..52c93521 100644 --- a/docs/source/Expand Exisiting Verifications.rst +++ b/docs/source/Expand Exisiting Verifications.rst @@ -20,4 +20,4 @@ Expand Exisiting Verifications self.result = (self.df["point_1"] > self.df["point_2"]) 2. The new verification class name should be added to the list of class already listed in the `__init__.py` file located in that same directory -3. A library file that includes all the information needed by the verification logic should be created or appended if it already exists \ No newline at end of file +3. A library file that includes all the information needed by the verification logic should be created or appended if it already exists diff --git a/docs/source/Quickstart Guide.rst b/docs/source/Quickstart Guide.rst index 95a43d87..302d54c7 100644 --- a/docs/source/Quickstart Guide.rst +++ b/docs/source/Quickstart Guide.rst @@ -10,6 +10,12 @@ Quickstart Guide This guide provides a quick overview of how to get started with **ConStrain**. Verifications of building system control related timeseries using **ConStrain** can either be done by using **ConStrain** as a Python library or by using a **ConStrain** workflow. +What? Who? How? +------------------ +**ConStrain** is a data-driven knowledge-integrated framework that automatically verifies that controls function as intended. As such, **ConStrain** might be of interest to a wide audience: from commissioning agents, to building operators, building energy modeling software users and developers and more. + +The first step towards using the tool is to gather timeseries data that can be used to verify a specific sequence of operation or the correct behavior of an equipment. **ConStrain**'s library_ provide a list of the different verifications that can be performed, not that they can it can be expanded see documentation section on that topic. For each, it provides some general description and references, and also provides a list of the data points needed to carry out verifications. For example, the ASHRAE Guideline 36 verification named `G36ReheatTerminalBoxDeadbandAirflowSetpoint` aims to very that terminal boxes with reheat when the zone state is deadband following the Guideline 36 recommendations as described in Section 5.6.5.2 in ASHRAE Guideline 36 2021. For this verification to be carried out, a user would have to gather timeseries (or static parameter values when applicable) for the following datapoints: system operation mode, zone state, minimum airflow setpoint during occupied mode, airflow setpoint, heating coil command, discharge air temperature, minimum discharge air temperature setpoint. Note that the timeseries can come from any sources: from a building management system or from simulation. When completed, one is ready to use ConStrain. Note that if the data needs to be pre-processed, **ConStrain**'s pre-processing API_ could help. + Installing **ConStrain** ------------------------- **ConStrain** can be installed from PyPI by running the following command. @@ -24,8 +30,8 @@ Running Verifications using **ConStrain** **ConStrain** relies on verification case files to perform verifications. These are JSON files that contain all the necessary information about data points, reference to verification logics, and simulation parameters when applicable. A verification case file can be built as follows: 1. Identify if the desired verification is already part of the default library. **ConStrain**'s default verifications are documented :doc:`here <../Verifications>`. If not, consider expanding the default verifications, help is provided :doc:`here <../Expand Exisiting Verifications>`. - 2. Create a JSON file that contains all the information needed by ConStrain to run the verification as detailed below or as defined on this schema (TBD). - 3. Run the verification either using **ConStrain** as a :ref:`library ` or using a **ConStrain** :ref:`workflow `. + 2. Create a JSON file that contains all the information needed by ConStrain to run the verification as detailed below or as defined in this schema_. + 3. Run the verification either using **ConStrain** as a :ref:`library ` or using a **ConStrain** :ref:`workflow `. .. sourcecode:: JSON @@ -74,7 +80,7 @@ Running Verifications using **ConStrain** } } -.. _library: +.. _lib: Using **ConStrain** as a Python Library ---------------------------------------- @@ -138,191 +144,88 @@ Finally, we can create summary report. A summary report for all verification wil reporting.report_multiple_cases() -.. _workflow: +.. _wf: -Using **ConStrain**'s' Workflows +Using **ConStrain**'s Workflows ---------------------------------- A workflow is a group of instructions that define an end-to-end verification, from data parsing and manipulation to running the verfication(s) and reporting the results. Workflows are defined using the JSON file format so once they have been established they can be re-used easily without making significant modifications. Workflows rely on **ConStrain**'s APIs. -Below is shown a valid workflow. - -.. sourcecode:: JSON - - { - "workflow_name": "G36 Demo workflow", - "meta": { - "author": "ConStrain Team", - "date": "06/29/2023", - "version": "1.0", - "description": "Demo workflow to showcase G36 verification item development" - }, - "imports": [ - "numpy as np", - "pandas as pd" - ], - "states": { - "load data": { - "Type": "MethodCall", - "MethodCall": "DataProcessing", - "Parameters": { - "data_path": "./demo/G36_demo/data/G36_Modelica_Jan.csv", - "data_source": "EnergyPlus" - }, - "Payloads": { - "data_processing_obj": "$", - "data": "$.data" - }, - "Start": "True", - "Next": "load verification cases" - }, - "load verification cases": { - "Type": "MethodCall", - "MethodCall": "VerificationCase", - "Parameters": { - "json_case_path": "./demo/G36_demo/data/G36_library_verification_cases.json" - }, - "Payloads": { - "verification_case_obj": "$", - "original_case_keys": "$.case_suite.keys()" - }, - "Next": "check original case length" - }, - "check original case length": { - "Type": "Choice", - "Choices": [ - { - "Value": "len(Payloads['original_case_keys']) == 3", - "Equals": "True", - "Next": "validate cases" - } - ], - "Default": "Report Error in workflow" - }, - "validate cases": { - "Type": "Choice", - "Choices": [ - { - "Value": "Payloads['verification_case_obj'].validate()", - "Equals": "True", - "Next": "setup verification" - } - ], - "Default": "Report Error in workflow" - }, - "setup verification": { - "Type": "MethodCall", - "MethodCall": "Verification", - "Parameters": { - "verifications": "Payloads['verification_case_obj']" - }, - "Payloads": { - "verification_obj": "$" - }, - "Next": "configure verification runner" - }, - "configure verification runner": { - "Type": "MethodCall", - "MethodCall": "Payloads['verification_obj'].configure", - "Parameters": { - "output_path": "./demo/G36_demo", - "lib_items_path": "./schema/library.json", - "plot_option": "+x None", - "fig_size": "+x (6, 5)", - "num_threads": 1, - "preprocessed_data": "Payloads['data']" - }, - "Payloads": {}, - "Next": "run verification" - }, - "run verification": { - "Type": "MethodCall", - "MethodCall": "Payloads['verification_obj'].run", - "Parameters": {}, - "Payloads": { - "verification_return": "$" - }, - "Next": "check results" - }, - "check results": { - "Type": "MethodCall", - "MethodCall": "glob.glob", - "Parameters": [ - "./demo/G36_demo/*_md.json" - ], - "Payloads": { - "length_of_mdjson": "len($)" - }, - "Next": "check number of result files" - }, - "check number of result files": { - "Type": "Choice", - "Choices": [ - { - "Value": "Payloads['length_of_mdjson']", - "Equals": "3", - "Next": "reporting_object_instantiation" - } - ], - "Default": "Report Error in workflow" - }, - "reporting_object_instantiation": { - "Type": "MethodCall", - "MethodCall": "Reporting", - "Parameters": { - "verification_json": "./demo/G36_demo/*_md.json", - "result_md_name": "report_summary.md", - "report_format": "markdown" - }, - "Payloads": { - "reporting_obj": "$" - }, - "Next": "report_cases" - }, - "report_cases": { - "Type": "MethodCall", - "MethodCall": "Payloads['reporting_obj'].report_multiple_cases", - "Parameters": {}, - "Payloads": {}, - "Next": "Success" - }, - "Success": { - "Type": "MethodCall", - "MethodCall": "print", - "Parameters": [ - "Congratulations! the demo workflow is executed with expected results and no error!" - ], - "End": "True" - }, - "Report Error in workflow": { - "Type": "MethodCall", - "MethodCall": "logging.error", - "Parameters": [ - "Something is wrong in the workflow execution" - ], - "End": "True" - } - } - } - -Where: +Here is a valid workflow_. Where: - :json:`"workflow_name"`: Name of the workflow - :json:`"meta"`: Metadata about the workflow - :json:`"imports"`: Python package import needed to run the workflow - :json:`"states"`: Sequential steps to follow to perform the verification; :json:`"states"` can either be :json:`"MethodCall"` which represent a method call to one of **ConStrain**'s APIs or a :json:`"Choice"` which can be used to help define alternative steps in a workflow based on the result (referred to as payloads in a workflow). -Running a workflow can be done as follows. +Running a workflow can be done as follows: .. sourcecode:: python import constrain as cs - - workflow_file = "./demo/G36_demo/G36_demo_workflow.json" - workflow = cs.Workflow(workflow=workflow_file) + import requests, json, os + from pathlib import Path + + # 1 - Get workflow file + url = "https://raw.githubusercontent.com/pnnl/ConStrain/refs/heads/develop/constrain/demo/G36_demo/G36_demo_workflow.json" + response = requests.get(url) + data = json.loads(response.content) + with open("G36_demo_workflow.json", "wb") as f: + f.write(response.content) + + # 2 - Get the timeseries + url_data = "https://raw.githubusercontent.com/pnnl/ConStrain/refs/heads/develop/constrain/demo/G36_demo/data/G36_Modelica_Jan.csv" + response = requests.get(url_data) + with open("./G36_Modelica_Jan.csv", "wb") as f: + f.write(response.content) + + # 3 - Get the verification cases + url_verification_cases = "https://raw.githubusercontent.com/pnnl/ConStrain/refs/heads/develop/constrain/demo/G36_demo/data/G36_library_verification_cases.json" + response = requests.get(url_verification_cases) + with open("./G36_library_verification_cases.json", "wb") as f: + f.write(response.content) + + # 3 - Get the ConStrain library + url_lib = "https://raw.githubusercontent.com/pnnl/ConStrain/refs/heads/develop/constrain/schema/library.json" + response = requests.get(url_lib) + with open("./library.json", "wb") as f: + f.write(response.content) + + # 4 - Change data path + data["states"]["load data"]["Parameters"]["data_path"] = str("./G36_Modelica_Jan.csv") + data["states"]["load verification cases"]["Parameters"]["json_case_path"] = str("./G36_library_verification_cases.json") + data["states"]["configure verification runner"]["Parameters"]["output_path"] = "./" + data["states"]["configure verification runner"]["Parameters"]["lib_items_path"] = ("./library.json") + data["states"]["check results"]["Parameters"][0] = "./*_md.json" + data["states"]["reporting_object_instantiation"]["Parameters"][ + "verification_json" + ] = "./*_md.json" + + # 3 - Run workflow + workflow = cs.Workflow(workflow=data) workflow.run_workflow(verbose=True) +Interpreting Results +--------------------- + +After running the verifications defined above, whether it is using **ConStrain** as a library or using its Workflow capability, a `report_summary.md` file will be generated. The files contains a table that provide high-level information about the verifications that have been performed, including: case index, name of the data set, type of verification, number of samples analyzed, number of successful verifications, number of failed verifications, number of untested samples, and a general pass/fail assessement for the verification. + +The markdown file contains hyperlinks so users can open a more detailed report for each verification. Detailed reports include three main sections: 1) Pass/Fail check results, 2) Result visualization, and 3) Verification case definition. The former is a repeat of what is included in the main summary report previously described. The Result visualization section shows, depending on the plotting option documented here_, one or multiple charts depicting for a specific time period or a day, the values of the different variables used by the verification and the results of the verification. The Pass / Fail flag plot shows passing verification as `1` and failing verifications as `0`. The last section provide a summary of settings used to perform the verification. + Using **ConStrain**'s Graphical User Interface (GUI) ----------------------------------------------------- -Workflow can be pretty complex and difficult to fully visualise from JSON files. **ConStrain** includes a GUI to help user create, edit, and picture workflows. If **ConStrain** has been installed, the GUI can be run by just running :bash:`constrain` in a command prompt or terminal. +Workflow can be pretty complex and difficult to fully visualise from JSON files. **ConStrain** includes a GUI to help user create, edit, and picture workflows. If **ConStrain** has been installed, the GUI can be run by just running :bash:`constrain` in a command prompt or terminal. It is documented in this file_. + +Brick Schema and **ConStrain** +-------------------------------- +**ConStrain** uses the the Brick Schema to automate the verification process. For additional information, see the how-to guide_. + +.. _schema: https://github.com/pnnl/ConStrain/blob/develop/constrain/schema/verification_cases.schema.json +.. _here: https://pnnl.github.io/ConStrain/Code%20Documentation.html#api.verification.Verification.configure +.. _library: https://github.com/pnnl/ConStrain/blob/develop/constrain/schema/library.json +.. _API: https://pnnl.github.io/ConStrain/Code%20Documentation.html#data-processing-py +.. _file: https://github.com/pnnl/ConStrain/blob/develop/constrain/app/README.md +.. _workflow: https://raw.githubusercontent.com/pnnl/ConStrain/refs/heads/develop/constrain/demo/G36_demo/G36_demo_workflow.json +.. _guide: https://github.com/pnnl/ConStrain/blob/develop/docs/brick_guide/brick_comment_new.md + diff --git a/docs/source/conf.py b/docs/source/conf.py index 8ec34caa..b2c30689 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -55,7 +55,7 @@ "sphinx.ext.viewcode", "sphinx.ext.githubpages", "sphinx.ext.autodoc", - #'sphinx.ext.napoleon' + "sphinx.ext.napoleon", ] # Add any paths that contain templates here, relative to this directory. diff --git a/pyproject.toml b/pyproject.toml index 6acb151e..f98aaf11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,13 @@ jsonschema= "^4.21.1" pre-commit = "^3.6.0" pytest = "^7.4.3" black = "24.3.0" +sphinx = "4.2.0" +sphinxcontrib-applehelp = "1.0.4" +sphinxcontrib-devhelp = "1.0.2" +sphinxcontrib-htmlhelp = "2.0.1" +sphinxcontrib-qthelp = "1.0.3" +sphinxcontrib-serializinghtml = "1.1.5" +sphinx-rtd-theme = "1.3.0" [build-system] requires = ["poetry-core"]