Skip to content

Commit

Permalink
rolling back on the BRICK features but its in the works
Browse files Browse the repository at this point in the history
  • Loading branch information
bbartling committed Aug 15, 2024
1 parent 6e2e71b commit 5beec62
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 158 deletions.
112 changes: 18 additions & 94 deletions open_fdd/air_handling_unit/faults/fault_condition_one.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,100 +8,26 @@ class FaultConditionOne(FaultCondition):
AHU low duct static pressure fan fault.
"""

def __init__(
self,
brick_graph,
column_mapping,
troubleshoot_mode=False,
rolling_window_size=10,
):
self.brick_graph = brick_graph
self.column_mapping = column_mapping # Now passed as an argument
self.troubleshoot_mode = troubleshoot_mode
self.rolling_window_size = rolling_window_size

# Placeholder for attributes, these will be assigned dynamically
self.duct_static_col = None
self.supply_vfd_speed_col = None
self.duct_static_setpoint_col = None

# Set default error thresholds and maximums
self.vfd_speed_percent_err_thres = 0.05
self.vfd_speed_percent_max = 0.99
self.duct_static_inches_err_thres = 0.1

# Assign the attributes by mapping URIs to DataFrame column names
self.assign_attributes()

def assign_attributes(self):
# Use the full URIs in the queries
duct_static_sensors = self.find_entities_of_type(
"https://brickschema.org/schema/1.1/Brick#Supply_Air_Static_Pressure_Sensor"
)
vfd_speed_sensors = self.find_entities_of_type(
"https://brickschema.org/schema/1.1/Brick#Supply_Fan_VFD_Speed_Sensor"
)
static_pressure_setpoints = self.find_entities_of_type(
"https://brickschema.org/schema/1.1/Brick#Static_Pressure_Setpoint"
)

# Debugging print statements to check what's found
print("Duct Static Sensors found:", duct_static_sensors)
print("VFD Speed Sensors found:", vfd_speed_sensors)
print("Static Pressure Setpoints found:", static_pressure_setpoints)

if not (
duct_static_sensors and vfd_speed_sensors and static_pressure_setpoints
):
raise ValueError("Required sensors are missing from the Brick model.")

# Assuming you want to map the first found instance to the corresponding column
self.duct_static_col = self.column_mapping.get(
str(duct_static_sensors[0]), None
)
self.supply_vfd_speed_col = self.column_mapping.get(
str(vfd_speed_sensors[0]), None
)
self.duct_static_setpoint_col = self.column_mapping.get(
str(static_pressure_setpoints[0]), None
)

# Debugging print statements to check the column mapping results
print("Mapped duct_static_col:", self.duct_static_col)
print("Mapped supply_vfd_speed_col:", self.supply_vfd_speed_col)
print("Mapped duct_static_setpoint_col:", self.duct_static_setpoint_col)

sys.stdout.flush()

# Raise an error if any of the columns were not mapped correctly
if None in [
self.duct_static_col,
self.supply_vfd_speed_col,
self.duct_static_setpoint_col,
]:
raise ValueError("Column mapping failed for one or more sensors.")

def find_entities_of_type(self, brick_class_uri):
query = f"""
SELECT ?s WHERE {{
?s rdf:type <{brick_class_uri}> .
}}
def __init__(self, dict_):
"""
:param dict_:
"""
results = self.brick_graph.query(query)
entities = [row.s for row in results]
if not entities:
print(f"No entities found for type: {brick_class_uri}")
return entities
self.vfd_speed_percent_err_thres = float
self.vfd_speed_percent_max = float
self.duct_static_inches_err_thres = float
self.duct_static_col = str
self.supply_vfd_speed_col = str
self.duct_static_setpoint_col = str
self.troubleshoot_mode = bool # default should be False
self.rolling_window_size = int

self.set_attributes(dict_)

def apply(self, df: pd.DataFrame) -> pd.DataFrame:
if self.troubleshoot_mode:
print(
"Troubleshoot mode enabled - additional debug information will be printed."
)
sys.stdout.flush()
self.troubleshoot_cols(df)

# Check analog outputs [data with units of %] are floats only
# check analog outputs [data with units of %] are floats only
columns_to_check = [self.supply_vfd_speed_col]
self.check_analog_pct(df, columns_to_check)

Expand All @@ -124,13 +50,11 @@ def apply(self, df: pd.DataFrame) -> pd.DataFrame:
# Set flag to 1 if rolling sum equals the window size
df["fc1_flag"] = (rolling_sum == self.rolling_window_size).astype(int)

if not self.troubleshoot_mode:
# Remove helper columns if not in troubleshoot mode
if self.troubleshoot_mode:
print("Troubleshoot mode enabled - not removing helper columns")
sys.stdout.flush()
del df["static_check_"]
del df["fan_check_"]
del df["combined_check"]
else:
print("Troubleshoot mode: retaining helper columns for debugging.")
sys.stdout.flush()

return df
return df
13 changes: 6 additions & 7 deletions open_fdd/air_handling_unit/reports/report_fc1.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@


class FaultCodeOneReport:
def __init__(self, fault_condition):
# We now expect the FaultConditionOne object instead of a config dictionary
self.duct_static_col = fault_condition.duct_static_col
self.supply_vfd_speed_col = fault_condition.supply_vfd_speed_col
self.duct_static_setpoint_col = fault_condition.duct_static_setpoint_col
self.vfd_speed_percent_err_thres = fault_condition.vfd_speed_percent_err_thres
def __init__(self, config):
self.vfd_speed_percent_err_thres = config["VFD_SPEED_PERCENT_ERR_THRES"]
self.duct_static_col = config["DUCT_STATIC_COL"]
self.supply_vfd_speed_col = config["SUPPLY_VFD_SPEED_COL"]
self.duct_static_setpoint_col = config["DUCT_STATIC_SETPOINT_COL"]

def create_plot(self, df: pd.DataFrame, output_col: str = None):
if output_col is None:
Expand Down Expand Up @@ -113,4 +112,4 @@ def display_report_in_ipython(self, df: pd.DataFrame, output_col: str = "fc1_fla

else:
print("NO FAULTS FOUND - Skipping time-of-day Histogram plot")
sys.stdout.flush()
sys.stdout.flush()
98 changes: 41 additions & 57 deletions open_fdd/tests/ahu/test_ahu_fc1.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,38 @@
import pytest
from open_fdd.air_handling_unit.faults.fault_condition_one import FaultConditionOne
from open_fdd.air_handling_unit.faults.helper_utils import HelperUtils
from rdflib import Graph, Namespace, URIRef, Literal
from rdflib import RDF


# Initialize the Brick graph and model
BRICK = Namespace("https://brickschema.org/schema/1.1/Brick#")
BRICKFRAME = Namespace("https://brickschema.org/schema/1.1/BrickFrame#")
brick_graph = Graph()

brick_graph.bind("brick", BRICK)
brick_graph.bind("brickframe", BRICKFRAME)

# Create the Air Handling Unit (AHU) and related sensors in the Brick model
ahu = URIRef("http://example.com/building/AHU1")
duct_static_sensor = URIRef(
"http://example.com/building/Supply_Air_Static_Pressure_Sensor"
)
vfd_speed_sensor = URIRef("http://example.com/building/Supply_Fan_VFD_Speed_Sensor")
static_pressure_setpoint = URIRef(
"http://example.com/building/Static_Pressure_Setpoint"
)

brick_graph.add((ahu, RDF.type, BRICK.Air_Handler_Unit))
brick_graph.add((duct_static_sensor, RDF.type, BRICK.Supply_Air_Static_Pressure_Sensor))
brick_graph.add((vfd_speed_sensor, RDF.type, BRICK.Supply_Fan_VFD_Speed_Sensor))
brick_graph.add((static_pressure_setpoint, RDF.type, BRICK.Static_Pressure_Setpoint))
brick_graph.add((ahu, BRICKFRAME.hasPoint, duct_static_sensor))
brick_graph.add((ahu, BRICKFRAME.hasPoint, vfd_speed_sensor))
brick_graph.add((ahu, BRICKFRAME.hasPoint, static_pressure_setpoint))

# Mapping from URIs to DataFrame column names
column_mapping = {
str(duct_static_sensor): "duct_static",
str(vfd_speed_sensor): "supply_vfd_speed",
str(static_pressure_setpoint): "duct_static_setpoint",

# Constants
TEST_VFD_ERR_THRESHOLD = 0.05
TEST_VFD_SPEED_MAX = 0.7
TEST_DUCT_STATIC_ERR_THRESHOLD = 0.1
TEST_DUCT_STATIC_COL = "duct_static"
TEST_DUCT_STATIC_SETPOINT_COL = "duct_static_setpoint"
TEST_SUPPLY_VFD_SPEED_COL = "supply_vfd_speed"
ROLLING_WINDOW_SIZE = 5

# Initialize FaultConditionOne with a dictionary
fault_condition_params = {
"VFD_SPEED_PERCENT_ERR_THRES": TEST_VFD_ERR_THRESHOLD,
"VFD_SPEED_PERCENT_MAX": TEST_VFD_SPEED_MAX,
"DUCT_STATIC_INCHES_ERR_THRES": TEST_DUCT_STATIC_ERR_THRESHOLD,
"DUCT_STATIC_COL": TEST_DUCT_STATIC_COL,
"SUPPLY_VFD_SPEED_COL": TEST_SUPPLY_VFD_SPEED_COL,
"DUCT_STATIC_SETPOINT_COL": TEST_DUCT_STATIC_SETPOINT_COL,
"TROUBLESHOOT_MODE": False, # default value
"ROLLING_WINDOW_SIZE": ROLLING_WINDOW_SIZE, # rolling sum window size
}

# Initialize FaultConditionOne with Brick model and column mapping
fc1 = FaultConditionOne(
brick_graph,
column_mapping=column_mapping,
troubleshoot_mode=False,
rolling_window_size=5,
)
fc1 = FaultConditionOne(fault_condition_params)


class TestNoFault:

def no_fault_df(self) -> pd.DataFrame:
data = {
"duct_static": [0.99, 0.99, 0.99, 0.99, 0.99, 0.99],
"duct_static_setpoint": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
"supply_vfd_speed": [0.8, 0.8, 0.8, 0.8, 0.8, 0.8],
TEST_DUCT_STATIC_COL: [0.99, 0.99, 0.99, 0.99, 0.99, 0.99],
TEST_DUCT_STATIC_SETPOINT_COL: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
TEST_SUPPLY_VFD_SPEED_COL: [0.8, 0.8, 0.8, 0.8, 0.8, 0.8],
}
return pd.DataFrame(data)

Expand All @@ -70,7 +49,7 @@ class TestFault:

def fault_df(self) -> pd.DataFrame:
data = {
"duct_static": [
TEST_DUCT_STATIC_COL: [
0.7,
0.7,
0.6,
Expand All @@ -89,7 +68,7 @@ def fault_df(self) -> pd.DataFrame:
0.55,
0.6,
],
"duct_static_setpoint": [
TEST_DUCT_STATIC_SETPOINT_COL: [
1.0,
1.0,
1.0,
Expand All @@ -108,7 +87,7 @@ def fault_df(self) -> pd.DataFrame:
1.0,
1.0,
],
"supply_vfd_speed": [
TEST_SUPPLY_VFD_SPEED_COL: [
0.99,
0.95,
0.96,
Expand All @@ -134,6 +113,11 @@ def test_fault(self):
results = fc1.apply(self.fault_df())
actual = results["fc1_flag"].sum()

# accumilated 5 faults need to happen before an "official fault"
# in TEST_DUCT_STATIC_COL after the 5 first values there is 3 faults
# then artificially adjust fake fan data back to normal and another 5
# needs happen per ROLLING_WINDOW_SIZE and then 4 faults after that.
# so expected = 3 + 4.
expected = 3 + 4
message = f"FC1 fault_df actual is {actual} and expected is {expected}"
assert actual == expected, message
Expand All @@ -143,16 +127,16 @@ class TestFaultOnInt:

def fault_df_on_output_int(self) -> pd.DataFrame:
data = {
"duct_static": [0.8] * 6,
"duct_static_setpoint": [1.0] * 6,
"supply_vfd_speed": [99] * 6,
TEST_DUCT_STATIC_COL: [0.8] * 6,
TEST_DUCT_STATIC_SETPOINT_COL: [1.0] * 6,
TEST_SUPPLY_VFD_SPEED_COL: [99] * 6,
}
return pd.DataFrame(data)

def test_fault_on_int(self):
with pytest.raises(
TypeError,
match=HelperUtils().float_int_check_err("supply_vfd_speed"),
match=HelperUtils().float_int_check_err(TEST_SUPPLY_VFD_SPEED_COL),
):
fc1.apply(self.fault_df_on_output_int())

Expand All @@ -161,15 +145,15 @@ class TestFaultOnFloatGreaterThanOne:

def fault_df_on_output_greater_than_one(self) -> pd.DataFrame:
data = {
"duct_static": [0.8] * 6,
"duct_static_setpoint": [1.0] * 6,
"supply_vfd_speed": [99.0] * 6,
TEST_DUCT_STATIC_COL: [0.8] * 6,
TEST_DUCT_STATIC_SETPOINT_COL: [1.0] * 6,
TEST_SUPPLY_VFD_SPEED_COL: [99.0] * 6,
}
return pd.DataFrame(data)

def test_fault_on_float_greater_than_one(self):
with pytest.raises(
TypeError,
match=HelperUtils().float_max_check_err("supply_vfd_speed"),
match=HelperUtils().float_max_check_err(TEST_SUPPLY_VFD_SPEED_COL),
):
fc1.apply(self.fault_df_on_output_greater_than_one())
fc1.apply(self.fault_df_on_output_greater_than_one())

0 comments on commit 5beec62

Please sign in to comment.