open-fdd 0.1.3__py3-none-any.whl → 0.1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- open_fdd/air_handling_unit/faults/__init__.py +2253 -0
- open_fdd/air_handling_unit/faults/fault_condition.py +12 -10
- open_fdd/air_handling_unit/faults/fault_condition_eight.py +38 -2
- open_fdd/air_handling_unit/faults/fault_condition_eleven.py +38 -2
- open_fdd/air_handling_unit/faults/fault_condition_fifteen.py +38 -2
- open_fdd/air_handling_unit/faults/fault_condition_five.py +38 -2
- open_fdd/air_handling_unit/faults/fault_condition_four.py +34 -2
- open_fdd/air_handling_unit/faults/fault_condition_fourteen.py +38 -2
- open_fdd/air_handling_unit/faults/fault_condition_nine.py +38 -2
- open_fdd/air_handling_unit/faults/fault_condition_one.py +37 -6
- open_fdd/air_handling_unit/faults/fault_condition_seven.py +38 -2
- open_fdd/air_handling_unit/faults/fault_condition_six.py +39 -2
- open_fdd/air_handling_unit/faults/fault_condition_ten.py +39 -3
- open_fdd/air_handling_unit/faults/fault_condition_thirteen.py +38 -2
- open_fdd/air_handling_unit/faults/fault_condition_three.py +32 -2
- open_fdd/air_handling_unit/faults/fault_condition_twelve.py +40 -3
- open_fdd/air_handling_unit/faults/fault_condition_two.py +32 -2
- open_fdd/air_handling_unit/faults/helper_utils.py +1 -29
- open_fdd/air_handling_unit/reports/__init__.py +894 -0
- open_fdd/air_handling_unit/reports/fault_report.py +41 -0
- open_fdd/tests/ahu/test_ahu_fc1.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc10.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc11.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc12.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc13.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc14.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc15.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc2.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc3.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc4.py +199 -127
- open_fdd/tests/ahu/test_ahu_fc5.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc6.py +2 -2
- open_fdd/tests/ahu/test_ahu_fc7.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc8.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc9.py +1 -1
- {open_fdd-0.1.3.dist-info → open_fdd-0.1.5.dist-info}/METADATA +21 -14
- {open_fdd-0.1.3.dist-info → open_fdd-0.1.5.dist-info}/RECORD +40 -39
- {open_fdd-0.1.3.dist-info → open_fdd-0.1.5.dist-info}/LICENSE +0 -0
- {open_fdd-0.1.3.dist-info → open_fdd-0.1.5.dist-info}/WHEEL +0 -0
- {open_fdd-0.1.3.dist-info → open_fdd-0.1.5.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,8 @@ import pandas.api.types as pdtypes
|
|
3
3
|
from open_fdd.air_handling_unit.faults.helper_utils import HelperUtils
|
4
4
|
import sys
|
5
5
|
|
6
|
+
"""see __init__.py for fault classes"""
|
7
|
+
|
6
8
|
|
7
9
|
class MissingColumnError(Exception):
|
8
10
|
"""Custom exception raised when a required column is missing or None."""
|
@@ -12,6 +14,14 @@ class MissingColumnError(Exception):
|
|
12
14
|
super().__init__(self.message)
|
13
15
|
|
14
16
|
|
17
|
+
class InvalidParameterError(Exception):
|
18
|
+
"""Custom exception raised when a parameter is not valid (e.g., not a float)."""
|
19
|
+
|
20
|
+
def __init__(self, message):
|
21
|
+
self.message = message
|
22
|
+
super().__init__(self.message)
|
23
|
+
|
24
|
+
|
15
25
|
class FaultCondition:
|
16
26
|
"""Parent class for Fault Conditions. Methods are inherited to all children."""
|
17
27
|
|
@@ -36,11 +46,7 @@ class FaultCondition:
|
|
36
46
|
raise MissingColumnError(f"Missing required columns: {missing_columns}")
|
37
47
|
|
38
48
|
def troubleshoot_cols(self, df):
|
39
|
-
"""
|
40
|
-
|
41
|
-
:param df:
|
42
|
-
:return:
|
43
|
-
"""
|
49
|
+
"""Print troubleshoot columns mapping."""
|
44
50
|
print("Troubleshoot mode enabled - not removing helper columns")
|
45
51
|
for col in df.columns:
|
46
52
|
print(
|
@@ -54,11 +60,7 @@ class FaultCondition:
|
|
54
60
|
sys.stdout.flush()
|
55
61
|
|
56
62
|
def check_analog_pct(self, df, columns):
|
57
|
-
"""
|
58
|
-
|
59
|
-
:param columns:
|
60
|
-
:return:
|
61
|
-
"""
|
63
|
+
"""Check analog outputs [data with units of %] are floats only."""
|
62
64
|
helper = HelperUtils()
|
63
65
|
for col in columns:
|
64
66
|
if not pdtypes.is_float_dtype(df[col]):
|
@@ -26,6 +26,20 @@ class FaultConditionEight(FaultCondition):
|
|
26
26
|
self.troubleshoot_mode = bool # default should be False
|
27
27
|
self.rolling_window_size = int
|
28
28
|
|
29
|
+
self.equation_string = (
|
30
|
+
"fc8_flag = 1 if |SAT - MAT - ΔT_fan| > √(εSAT² + εMAT²) "
|
31
|
+
"in economizer mode for N consecutive values else 0 \n"
|
32
|
+
)
|
33
|
+
self.description_string = (
|
34
|
+
"Fault Condition 8: Supply air temperature and mixed air temperature should "
|
35
|
+
"be approximately equal in economizer mode \n"
|
36
|
+
)
|
37
|
+
self.required_column_description = (
|
38
|
+
"Required inputs are the mixed air temperature, supply air temperature, "
|
39
|
+
"economizer signal, and cooling signal \n"
|
40
|
+
)
|
41
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
42
|
+
|
29
43
|
self.set_attributes(dict_)
|
30
44
|
|
31
45
|
# Set required columns specific to this fault condition
|
@@ -36,9 +50,31 @@ class FaultConditionEight(FaultCondition):
|
|
36
50
|
self.cooling_sig_col,
|
37
51
|
]
|
38
52
|
|
53
|
+
# Check if any of the required columns are None
|
54
|
+
if any(col is None for col in self.required_columns):
|
55
|
+
raise MissingColumnError(
|
56
|
+
f"{self.error_string}"
|
57
|
+
f"{self.equation_string}"
|
58
|
+
f"{self.description_string}"
|
59
|
+
f"{self.required_column_description}"
|
60
|
+
f"{self.required_columns}"
|
61
|
+
)
|
62
|
+
|
63
|
+
# Ensure all required columns are strings
|
64
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
65
|
+
|
66
|
+
self.mapped_columns = (
|
67
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
68
|
+
)
|
69
|
+
|
39
70
|
def get_required_columns(self) -> str:
|
40
71
|
"""Returns a string representation of the required columns."""
|
41
|
-
return
|
72
|
+
return (
|
73
|
+
f"{self.equation_string}"
|
74
|
+
f"{self.description_string}"
|
75
|
+
f"{self.required_column_description}"
|
76
|
+
f"{self.mapped_columns}"
|
77
|
+
)
|
42
78
|
|
43
79
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
44
80
|
try:
|
@@ -88,4 +124,4 @@ class FaultConditionEight(FaultCondition):
|
|
88
124
|
except MissingColumnError as e:
|
89
125
|
print(f"Error: {e.message}")
|
90
126
|
sys.stdout.flush()
|
91
|
-
raise e
|
127
|
+
raise e
|
@@ -25,6 +25,20 @@ class FaultConditionEleven(FaultCondition):
|
|
25
25
|
self.troubleshoot_mode = bool # default False
|
26
26
|
self.rolling_window_size = int
|
27
27
|
|
28
|
+
self.equation_string = (
|
29
|
+
"fc11_flag = 1 if OAT < (SATSP - ΔT_fan - εSAT) in "
|
30
|
+
"economizer cooling mode for N consecutive values else 0 \n"
|
31
|
+
)
|
32
|
+
self.description_string = (
|
33
|
+
"Fault Condition 11: Outside air temperature too low for 100% outdoor air cooling "
|
34
|
+
"in economizer cooling mode (Economizer performance fault) \n"
|
35
|
+
)
|
36
|
+
self.required_column_description = (
|
37
|
+
"Required inputs are the supply air temperature setpoint, outside air temperature, "
|
38
|
+
"cooling signal, and economizer signal \n"
|
39
|
+
)
|
40
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
41
|
+
|
28
42
|
self.set_attributes(dict_)
|
29
43
|
|
30
44
|
# Set required columns specific to this fault condition
|
@@ -35,9 +49,31 @@ class FaultConditionEleven(FaultCondition):
|
|
35
49
|
self.economizer_sig_col,
|
36
50
|
]
|
37
51
|
|
52
|
+
# Check if any of the required columns are None
|
53
|
+
if any(col is None for col in self.required_columns):
|
54
|
+
raise MissingColumnError(
|
55
|
+
f"{self.error_string}"
|
56
|
+
f"{self.equation_string}"
|
57
|
+
f"{self.description_string}"
|
58
|
+
f"{self.required_column_description}"
|
59
|
+
f"{self.required_columns}"
|
60
|
+
)
|
61
|
+
|
62
|
+
# Ensure all required columns are strings
|
63
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
64
|
+
|
65
|
+
self.mapped_columns = (
|
66
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
67
|
+
)
|
68
|
+
|
38
69
|
def get_required_columns(self) -> str:
|
39
70
|
"""Returns a string representation of the required columns."""
|
40
|
-
return
|
71
|
+
return (
|
72
|
+
f"{self.equation_string}"
|
73
|
+
f"{self.description_string}"
|
74
|
+
f"{self.required_column_description}"
|
75
|
+
f"{self.mapped_columns}"
|
76
|
+
)
|
41
77
|
|
42
78
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
43
79
|
try:
|
@@ -87,4 +123,4 @@ class FaultConditionEleven(FaultCondition):
|
|
87
123
|
except MissingColumnError as e:
|
88
124
|
print(f"Error: {e.message}")
|
89
125
|
sys.stdout.flush()
|
90
|
-
raise e
|
126
|
+
raise e
|
@@ -28,6 +28,20 @@ class FaultConditionFifteen(FaultCondition):
|
|
28
28
|
self.troubleshoot_mode = bool # default to False
|
29
29
|
self.rolling_window_size = int
|
30
30
|
|
31
|
+
self.equation_string = (
|
32
|
+
"fc15_flag = 1 if ΔT_coil >= √(εcoil_enter² + εcoil_leave²) + ΔT_fan "
|
33
|
+
"in inactive heating coil mode for N consecutive values else 0 \n"
|
34
|
+
)
|
35
|
+
self.description_string = (
|
36
|
+
"Fault Condition 15: Temperature rise across inactive heating coil "
|
37
|
+
"detected, requiring coil leaving temperature sensor \n"
|
38
|
+
)
|
39
|
+
self.required_column_description = (
|
40
|
+
"Required inputs are the heating coil entering temperature, heating coil leaving temperature, "
|
41
|
+
"cooling signal, heating signal, economizer signal, and supply fan VFD speed \n"
|
42
|
+
)
|
43
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
44
|
+
|
31
45
|
self.set_attributes(dict_)
|
32
46
|
|
33
47
|
# Set required columns specific to this fault condition
|
@@ -40,9 +54,31 @@ class FaultConditionFifteen(FaultCondition):
|
|
40
54
|
self.supply_vfd_speed_col,
|
41
55
|
]
|
42
56
|
|
57
|
+
# Check if any of the required columns are None
|
58
|
+
if any(col is None for col in self.required_columns):
|
59
|
+
raise MissingColumnError(
|
60
|
+
f"{self.error_string}"
|
61
|
+
f"{self.equation_string}"
|
62
|
+
f"{self.description_string}"
|
63
|
+
f"{self.required_column_description}"
|
64
|
+
f"{self.required_columns}"
|
65
|
+
)
|
66
|
+
|
67
|
+
# Ensure all required columns are strings
|
68
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
69
|
+
|
70
|
+
self.mapped_columns = (
|
71
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
72
|
+
)
|
73
|
+
|
43
74
|
def get_required_columns(self) -> str:
|
44
75
|
"""Returns a string representation of the required columns."""
|
45
|
-
return
|
76
|
+
return (
|
77
|
+
f"{self.equation_string}"
|
78
|
+
f"{self.description_string}"
|
79
|
+
f"{self.required_column_description}"
|
80
|
+
f"{self.mapped_columns}"
|
81
|
+
)
|
46
82
|
|
47
83
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
48
84
|
try:
|
@@ -113,4 +149,4 @@ class FaultConditionFifteen(FaultCondition):
|
|
113
149
|
except MissingColumnError as e:
|
114
150
|
print(f"Error: {e.message}")
|
115
151
|
sys.stdout.flush()
|
116
|
-
raise e
|
152
|
+
raise e
|
@@ -26,6 +26,20 @@ class FaultConditionFive(FaultCondition):
|
|
26
26
|
self.troubleshoot_mode = bool # default to False
|
27
27
|
self.rolling_window_size = int
|
28
28
|
|
29
|
+
self.equation_string = (
|
30
|
+
"fc5_flag = 1 if (SAT + εSAT <= MAT - εMAT + ΔT_supply_fan) and "
|
31
|
+
"(heating signal > 0) and (VFDSPD > 0) for N consecutive values else 0 \n"
|
32
|
+
)
|
33
|
+
self.description_string = (
|
34
|
+
"Fault Condition 5: SAT too low; should be higher than MAT in HTG MODE, "
|
35
|
+
"potential broken heating valve or mechanical issue \n"
|
36
|
+
)
|
37
|
+
self.required_column_description = (
|
38
|
+
"Required inputs are the mixed air temperature, supply air temperature, "
|
39
|
+
"heating signal, and supply fan VFD speed \n"
|
40
|
+
)
|
41
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
42
|
+
|
29
43
|
self.set_attributes(dict_)
|
30
44
|
|
31
45
|
# Set required columns specific to this fault condition
|
@@ -36,9 +50,31 @@ class FaultConditionFive(FaultCondition):
|
|
36
50
|
self.supply_vfd_speed_col,
|
37
51
|
]
|
38
52
|
|
53
|
+
# Check if any of the required columns are None
|
54
|
+
if any(col is None for col in self.required_columns):
|
55
|
+
raise MissingColumnError(
|
56
|
+
f"{self.error_string}"
|
57
|
+
f"{self.equation_string}"
|
58
|
+
f"{self.description_string}"
|
59
|
+
f"{self.required_column_description}"
|
60
|
+
f"{self.required_columns}"
|
61
|
+
)
|
62
|
+
|
63
|
+
# Ensure all required columns are strings
|
64
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
65
|
+
|
66
|
+
self.mapped_columns = (
|
67
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
68
|
+
)
|
69
|
+
|
39
70
|
def get_required_columns(self) -> str:
|
40
71
|
"""Returns a string representation of the required columns."""
|
41
|
-
return
|
72
|
+
return (
|
73
|
+
f"{self.equation_string}"
|
74
|
+
f"{self.description_string}"
|
75
|
+
f"{self.required_column_description}"
|
76
|
+
f"{self.mapped_columns}"
|
77
|
+
)
|
42
78
|
|
43
79
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
44
80
|
try:
|
@@ -84,4 +120,4 @@ class FaultConditionFive(FaultCondition):
|
|
84
120
|
except MissingColumnError as e:
|
85
121
|
print(f"Error: {e.message}")
|
86
122
|
sys.stdout.flush()
|
87
|
-
raise e
|
123
|
+
raise e
|
@@ -26,6 +26,17 @@ class FaultConditionFour(FaultCondition):
|
|
26
26
|
self.supply_vfd_speed_col = str
|
27
27
|
self.troubleshoot_mode = bool # default to False
|
28
28
|
|
29
|
+
self.equation_string = (
|
30
|
+
"fc4_flag = 1 if excessive mode changes (> δOS_max) occur "
|
31
|
+
"within an hour across heating, econ, econ+mech, mech clg, and min OA modes \n"
|
32
|
+
)
|
33
|
+
self.description_string = "Fault Condition 4: Excessive AHU operating state changes detected (hunting behavior) \n"
|
34
|
+
self.required_column_description = (
|
35
|
+
"Required inputs are the economizer signal, supply fan VFD speed, "
|
36
|
+
"and optionally heating and cooling signals \n"
|
37
|
+
)
|
38
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
39
|
+
|
29
40
|
self.set_attributes(dict_)
|
30
41
|
|
31
42
|
# Set required columns, making heating and cooling optional
|
@@ -40,9 +51,30 @@ class FaultConditionFour(FaultCondition):
|
|
40
51
|
if self.cooling_sig_col:
|
41
52
|
self.required_columns.append(self.cooling_sig_col)
|
42
53
|
|
54
|
+
# Check if any of the required columns are None
|
55
|
+
if any(col is None for col in self.required_columns):
|
56
|
+
raise MissingColumnError(
|
57
|
+
f"{self.error_string}"
|
58
|
+
f"{self.equation_string}"
|
59
|
+
f"{self.description_string}"
|
60
|
+
f"{self.required_column_description}"
|
61
|
+
f"{self.required_columns}"
|
62
|
+
)
|
63
|
+
# Ensure all required columns are strings
|
64
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
65
|
+
|
66
|
+
self.mapped_columns = (
|
67
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
68
|
+
)
|
69
|
+
|
43
70
|
def get_required_columns(self) -> str:
|
44
71
|
"""Returns a string representation of the required columns."""
|
45
|
-
return
|
72
|
+
return (
|
73
|
+
f"{self.equation_string}"
|
74
|
+
f"{self.description_string}"
|
75
|
+
f"{self.required_column_description}"
|
76
|
+
f"{self.mapped_columns}"
|
77
|
+
)
|
46
78
|
|
47
79
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
48
80
|
try:
|
@@ -133,4 +165,4 @@ class FaultConditionFour(FaultCondition):
|
|
133
165
|
except MissingColumnError as e:
|
134
166
|
print(f"Error: {e.message}")
|
135
167
|
sys.stdout.flush()
|
136
|
-
raise e
|
168
|
+
raise e
|
@@ -29,6 +29,20 @@ class FaultConditionFourteen(FaultCondition):
|
|
29
29
|
self.troubleshoot_mode = bool # default to False
|
30
30
|
self.rolling_window_size = int
|
31
31
|
|
32
|
+
self.equation_string = (
|
33
|
+
"fc14_flag = 1 if ΔT_coil >= √(εcoil_enter² + εcoil_leave²) + ΔT_fan "
|
34
|
+
"in inactive cooling coil mode for N consecutive values else 0 \n"
|
35
|
+
)
|
36
|
+
self.description_string = (
|
37
|
+
"Fault Condition 14: Temperature drop across inactive cooling coil "
|
38
|
+
"detected, requiring coil leaving temperature sensor \n"
|
39
|
+
)
|
40
|
+
self.required_column_description = (
|
41
|
+
"Required inputs are the cooling coil entering temperature, cooling coil leaving temperature, "
|
42
|
+
"cooling signal, heating signal, economizer signal, and supply fan VFD speed \n"
|
43
|
+
)
|
44
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
45
|
+
|
32
46
|
self.set_attributes(dict_)
|
33
47
|
|
34
48
|
# Set required columns specific to this fault condition
|
@@ -41,9 +55,31 @@ class FaultConditionFourteen(FaultCondition):
|
|
41
55
|
self.supply_vfd_speed_col,
|
42
56
|
]
|
43
57
|
|
58
|
+
# Check if any of the required columns are None
|
59
|
+
if any(col is None for col in self.required_columns):
|
60
|
+
raise MissingColumnError(
|
61
|
+
f"{self.error_string}"
|
62
|
+
f"{self.equation_string}"
|
63
|
+
f"{self.description_string}"
|
64
|
+
f"{self.required_column_description}"
|
65
|
+
f"{self.required_columns}"
|
66
|
+
)
|
67
|
+
|
68
|
+
# Ensure all required columns are strings
|
69
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
70
|
+
|
71
|
+
self.mapped_columns = (
|
72
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
73
|
+
)
|
74
|
+
|
44
75
|
def get_required_columns(self) -> str:
|
45
76
|
"""Returns a string representation of the required columns."""
|
46
|
-
return
|
77
|
+
return (
|
78
|
+
f"{self.equation_string}"
|
79
|
+
f"{self.description_string}"
|
80
|
+
f"{self.required_column_description}"
|
81
|
+
f"{self.mapped_columns}"
|
82
|
+
)
|
47
83
|
|
48
84
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
49
85
|
try:
|
@@ -104,4 +140,4 @@ class FaultConditionFourteen(FaultCondition):
|
|
104
140
|
except MissingColumnError as e:
|
105
141
|
print(f"Error: {e.message}")
|
106
142
|
sys.stdout.flush()
|
107
|
-
raise e
|
143
|
+
raise e
|
@@ -26,6 +26,20 @@ class FaultConditionNine(FaultCondition):
|
|
26
26
|
self.troubleshoot_mode = bool # default should be False
|
27
27
|
self.rolling_window_size = int
|
28
28
|
|
29
|
+
self.equation_string = (
|
30
|
+
"fc9_flag = 1 if OAT > (SATSP - ΔT_fan + εSAT) "
|
31
|
+
"in free cooling mode for N consecutive values else 0 \n"
|
32
|
+
)
|
33
|
+
self.description_string = (
|
34
|
+
"Fault Condition 9: Outside air temperature too high in free cooling mode "
|
35
|
+
"without additional mechanical cooling in economizer mode \n"
|
36
|
+
)
|
37
|
+
self.required_column_description = (
|
38
|
+
"Required inputs are the supply air temperature setpoint, outside air temperature, "
|
39
|
+
"cooling signal, and economizer signal \n"
|
40
|
+
)
|
41
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
42
|
+
|
29
43
|
self.set_attributes(dict_)
|
30
44
|
|
31
45
|
# Set required columns specific to this fault condition
|
@@ -36,9 +50,31 @@ class FaultConditionNine(FaultCondition):
|
|
36
50
|
self.economizer_sig_col,
|
37
51
|
]
|
38
52
|
|
53
|
+
# Check if any of the required columns are None
|
54
|
+
if any(col is None for col in self.required_columns):
|
55
|
+
raise MissingColumnError(
|
56
|
+
f"{self.error_string}"
|
57
|
+
f"{self.equation_string}"
|
58
|
+
f"{self.description_string}"
|
59
|
+
f"{self.required_column_description}"
|
60
|
+
f"{self.required_columns}"
|
61
|
+
)
|
62
|
+
|
63
|
+
# Ensure all required columns are strings
|
64
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
65
|
+
|
66
|
+
self.mapped_columns = (
|
67
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
68
|
+
)
|
69
|
+
|
39
70
|
def get_required_columns(self) -> str:
|
40
71
|
"""Returns a string representation of the required columns."""
|
41
|
-
return
|
72
|
+
return (
|
73
|
+
f"{self.equation_string}"
|
74
|
+
f"{self.description_string}"
|
75
|
+
f"{self.required_column_description}"
|
76
|
+
f"{self.mapped_columns}"
|
77
|
+
)
|
42
78
|
|
43
79
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
44
80
|
try:
|
@@ -89,4 +125,4 @@ class FaultConditionNine(FaultCondition):
|
|
89
125
|
except MissingColumnError as e:
|
90
126
|
print(f"Error: {e.message}")
|
91
127
|
sys.stdout.flush()
|
92
|
-
raise e
|
128
|
+
raise e
|
@@ -22,6 +22,13 @@ class FaultConditionOne(FaultCondition):
|
|
22
22
|
self.troubleshoot_mode = bool # default should be False
|
23
23
|
self.rolling_window_size = int
|
24
24
|
|
25
|
+
self.equation_string = "fc1_flag = 1 if (DSP < DPSP - εDSP) and (VFDSPD >= VFDSPD_max - εVFDSPD) for N consecutive values else 0 \n"
|
26
|
+
self.description_string = (
|
27
|
+
"Fault Condition 1: Duct static too low at fan at full speed \n"
|
28
|
+
)
|
29
|
+
self.required_column_description = "Required inputs are the duct static pressure, setpoint, and supply fan VFD speed \n"
|
30
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
31
|
+
|
25
32
|
self.set_attributes(dict_)
|
26
33
|
|
27
34
|
# Set required columns specific to this fault condition manually
|
@@ -31,9 +38,31 @@ class FaultConditionOne(FaultCondition):
|
|
31
38
|
self.duct_static_setpoint_col,
|
32
39
|
]
|
33
40
|
|
41
|
+
# Check if any of the required columns are None
|
42
|
+
if any(col is None for col in self.required_columns):
|
43
|
+
raise MissingColumnError(
|
44
|
+
f"{self.error_string}"
|
45
|
+
f"{self.equation_string}"
|
46
|
+
f"{self.description_string}"
|
47
|
+
f"{self.required_column_description}"
|
48
|
+
f"{self.required_columns}"
|
49
|
+
)
|
50
|
+
|
51
|
+
# Ensure all required columns are strings
|
52
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
53
|
+
|
54
|
+
self.mapped_columns = (
|
55
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
56
|
+
)
|
57
|
+
|
34
58
|
def get_required_columns(self) -> str:
|
35
|
-
"""
|
36
|
-
return
|
59
|
+
"""called from IPython to print out"""
|
60
|
+
return (
|
61
|
+
f"{self.equation_string}"
|
62
|
+
f"{self.description_string}"
|
63
|
+
f"{self.required_column_description}"
|
64
|
+
f"{self.mapped_columns}"
|
65
|
+
)
|
37
66
|
|
38
67
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
39
68
|
try:
|
@@ -69,13 +98,15 @@ class FaultConditionOne(FaultCondition):
|
|
69
98
|
if self.troubleshoot_mode:
|
70
99
|
print("Troubleshoot mode enabled - not removing helper columns")
|
71
100
|
sys.stdout.flush()
|
72
|
-
|
73
|
-
|
74
|
-
|
101
|
+
|
102
|
+
# Optionally remove temporary columns
|
103
|
+
df.drop(
|
104
|
+
columns=["static_check_", "fan_check_", "combined_check"], inplace=True
|
105
|
+
)
|
75
106
|
|
76
107
|
return df
|
77
108
|
|
78
109
|
except MissingColumnError as e:
|
79
110
|
print(f"Error: {e.message}")
|
80
111
|
sys.stdout.flush()
|
81
|
-
raise e
|
112
|
+
raise e
|
@@ -22,6 +22,20 @@ class FaultConditionSeven(FaultCondition):
|
|
22
22
|
self.troubleshoot_mode = bool # default to False
|
23
23
|
self.rolling_window_size = int
|
24
24
|
|
25
|
+
self.equation_string = (
|
26
|
+
"fc7_flag = 1 if SAT < (SATSP - εSAT) in full heating mode "
|
27
|
+
"and VFD speed > 0 for N consecutive values else 0 \n"
|
28
|
+
)
|
29
|
+
self.description_string = (
|
30
|
+
"Fault Condition 7: Supply air temperature too low in full heating mode "
|
31
|
+
"with heating valve fully open \n"
|
32
|
+
)
|
33
|
+
self.required_column_description = (
|
34
|
+
"Required inputs are the supply air temperature, supply air temperature setpoint, "
|
35
|
+
"heating signal, and supply fan VFD speed \n"
|
36
|
+
)
|
37
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
38
|
+
|
25
39
|
self.set_attributes(dict_)
|
26
40
|
|
27
41
|
# Set required columns specific to this fault condition
|
@@ -32,9 +46,31 @@ class FaultConditionSeven(FaultCondition):
|
|
32
46
|
self.supply_vfd_speed_col,
|
33
47
|
]
|
34
48
|
|
49
|
+
# Check if any of the required columns are None
|
50
|
+
if any(col is None for col in self.required_columns):
|
51
|
+
raise MissingColumnError(
|
52
|
+
f"{self.error_string}"
|
53
|
+
f"{self.equation_string}"
|
54
|
+
f"{self.description_string}"
|
55
|
+
f"{self.required_column_description}"
|
56
|
+
f"{self.required_columns}"
|
57
|
+
)
|
58
|
+
|
59
|
+
# Ensure all required columns are strings
|
60
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
61
|
+
|
62
|
+
self.mapped_columns = (
|
63
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
64
|
+
)
|
65
|
+
|
35
66
|
def get_required_columns(self) -> str:
|
36
67
|
"""Returns a string representation of the required columns."""
|
37
|
-
return
|
68
|
+
return (
|
69
|
+
f"{self.equation_string}"
|
70
|
+
f"{self.description_string}"
|
71
|
+
f"{self.required_column_description}"
|
72
|
+
f"{self.mapped_columns}"
|
73
|
+
)
|
38
74
|
|
39
75
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
40
76
|
try:
|
@@ -75,4 +111,4 @@ class FaultConditionSeven(FaultCondition):
|
|
75
111
|
except MissingColumnError as e:
|
76
112
|
print(f"Error: {e.message}")
|
77
113
|
sys.stdout.flush()
|
78
|
-
raise e
|
114
|
+
raise e
|
@@ -41,6 +41,21 @@ class FaultConditionSix(FaultCondition):
|
|
41
41
|
self.troubleshoot_mode = bool # default should be False
|
42
42
|
self.rolling_window_size = int
|
43
43
|
|
44
|
+
self.equation_string = (
|
45
|
+
"fc6_flag = 1 if |OA_frac_calc - OA_min| > airflow_err_thres "
|
46
|
+
"in non-economizer modes, considering htg and mech clg OS \n"
|
47
|
+
)
|
48
|
+
self.description_string = (
|
49
|
+
"Fault Condition 6: Issues detected with OA fraction calculation or AHU "
|
50
|
+
"not maintaining design air flow in non-economizer conditions \n"
|
51
|
+
)
|
52
|
+
self.required_column_description = (
|
53
|
+
"Required inputs are the supply fan air volume, mixed air temperature, "
|
54
|
+
"outside air temperature, return air temperature, and VFD speed. "
|
55
|
+
"Optional inputs include economizer signal, heating signal, and cooling signal \n"
|
56
|
+
)
|
57
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
58
|
+
|
44
59
|
self.set_attributes(dict_)
|
45
60
|
|
46
61
|
# Set required columns specific to this fault condition
|
@@ -55,9 +70,31 @@ class FaultConditionSix(FaultCondition):
|
|
55
70
|
self.cooling_sig_col,
|
56
71
|
]
|
57
72
|
|
73
|
+
# Check if any of the required columns are None
|
74
|
+
if any(col is None for col in self.required_columns):
|
75
|
+
raise MissingColumnError(
|
76
|
+
f"{self.error_string}"
|
77
|
+
f"{self.equation_string}"
|
78
|
+
f"{self.description_string}"
|
79
|
+
f"{self.required_column_description}"
|
80
|
+
f"{self.required_columns}"
|
81
|
+
)
|
82
|
+
|
83
|
+
# Ensure all required columns are strings
|
84
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
85
|
+
|
86
|
+
self.mapped_columns = (
|
87
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
88
|
+
)
|
89
|
+
|
58
90
|
def get_required_columns(self) -> str:
|
59
91
|
"""Returns a string representation of the required columns."""
|
60
|
-
return
|
92
|
+
return (
|
93
|
+
f"{self.equation_string}"
|
94
|
+
f"{self.description_string}"
|
95
|
+
f"{self.required_column_description}"
|
96
|
+
f"{self.mapped_columns}"
|
97
|
+
)
|
61
98
|
|
62
99
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
63
100
|
try:
|
@@ -141,4 +178,4 @@ class FaultConditionSix(FaultCondition):
|
|
141
178
|
except MissingColumnError as e:
|
142
179
|
print(f"Error: {e.message}")
|
143
180
|
sys.stdout.flush()
|
144
|
-
raise e
|
181
|
+
raise e
|