open-fdd 0.1.4__py3-none-any.whl → 0.1.6__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 +301 -301
- open_fdd/air_handling_unit/reports/__init__.py +988 -0
- open_fdd/air_handling_unit/reports/fault_report.py +42 -0
- open_fdd/tests/ahu/test_ahu_fc16.py +190 -0
- {open_fdd-0.1.4.dist-info → open_fdd-0.1.6.dist-info}/METADATA +21 -12
- open_fdd-0.1.6.dist-info/RECORD +31 -0
- {open_fdd-0.1.4.dist-info → open_fdd-0.1.6.dist-info}/WHEEL +1 -1
- open_fdd/air_handling_unit/faults/fault_condition_eight.py +0 -127
- open_fdd/air_handling_unit/faults/fault_condition_eleven.py +0 -126
- open_fdd/air_handling_unit/faults/fault_condition_fifteen.py +0 -152
- open_fdd/air_handling_unit/faults/fault_condition_five.py +0 -123
- open_fdd/air_handling_unit/faults/fault_condition_four.py +0 -168
- open_fdd/air_handling_unit/faults/fault_condition_fourteen.py +0 -143
- open_fdd/air_handling_unit/faults/fault_condition_nine.py +0 -128
- open_fdd/air_handling_unit/faults/fault_condition_one.py +0 -112
- open_fdd/air_handling_unit/faults/fault_condition_seven.py +0 -114
- open_fdd/air_handling_unit/faults/fault_condition_six.py +0 -181
- open_fdd/air_handling_unit/faults/fault_condition_ten.py +0 -123
- open_fdd/air_handling_unit/faults/fault_condition_thirteen.py +0 -127
- open_fdd/air_handling_unit/faults/fault_condition_three.py +0 -113
- open_fdd/air_handling_unit/faults/fault_condition_twelve.py +0 -132
- open_fdd/air_handling_unit/faults/fault_condition_two.py +0 -113
- open_fdd/air_handling_unit/images/ahu1_fc1_2024-06_1.jpg +0 -0
- open_fdd/air_handling_unit/images/ahu1_fc1_2024-06_2.jpg +0 -0
- open_fdd/air_handling_unit/images/example1.jpg +0 -0
- open_fdd/air_handling_unit/images/example2.jpg +0 -0
- open_fdd/air_handling_unit/images/fc10_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc11_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc12_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc13_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc1_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc1_report_screenshot_all.png +0 -0
- open_fdd/air_handling_unit/images/fc2_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc3_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc4_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc5_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc6_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc7_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc8_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc9_definition.png +0 -0
- open_fdd/air_handling_unit/images/latex_generator.py +0 -175
- open_fdd/air_handling_unit/images/params.docx +0 -0
- open_fdd/air_handling_unit/images/params.pdf +0 -0
- open_fdd/air_handling_unit/images/plot_for_repo.png +0 -0
- open_fdd/air_handling_unit/reports/base_report.py +0 -47
- open_fdd/air_handling_unit/reports/report_fc1.py +0 -115
- open_fdd/air_handling_unit/reports/report_fc10.py +0 -126
- open_fdd/air_handling_unit/reports/report_fc11.py +0 -128
- open_fdd/air_handling_unit/reports/report_fc12.py +0 -126
- open_fdd/air_handling_unit/reports/report_fc13.py +0 -126
- open_fdd/air_handling_unit/reports/report_fc14.py +0 -124
- open_fdd/air_handling_unit/reports/report_fc15.py +0 -124
- open_fdd/air_handling_unit/reports/report_fc2.py +0 -119
- open_fdd/air_handling_unit/reports/report_fc3.py +0 -119
- open_fdd/air_handling_unit/reports/report_fc4.py +0 -148
- open_fdd/air_handling_unit/reports/report_fc5.py +0 -132
- open_fdd/air_handling_unit/reports/report_fc6.py +0 -156
- open_fdd/air_handling_unit/reports/report_fc7.py +0 -126
- open_fdd/air_handling_unit/reports/report_fc8.py +0 -118
- open_fdd/air_handling_unit/reports/report_fc9.py +0 -120
- open_fdd-0.1.4.dist-info/RECORD +0 -82
- {open_fdd-0.1.4.dist-info → open_fdd-0.1.6.dist-info}/LICENSE +0 -0
- {open_fdd-0.1.4.dist-info → open_fdd-0.1.6.dist-info}/top_level.txt +0 -0
@@ -1,128 +0,0 @@
|
|
1
|
-
import pandas as pd
|
2
|
-
import numpy as np
|
3
|
-
from open_fdd.air_handling_unit.faults.fault_condition import (
|
4
|
-
FaultCondition,
|
5
|
-
MissingColumnError,
|
6
|
-
)
|
7
|
-
import sys
|
8
|
-
|
9
|
-
|
10
|
-
class FaultConditionNine(FaultCondition):
|
11
|
-
"""Class provides the definitions for Fault Condition 9.
|
12
|
-
Outside air temperature too high in free cooling without
|
13
|
-
additional mechanical cooling in economizer mode.
|
14
|
-
"""
|
15
|
-
|
16
|
-
def __init__(self, dict_):
|
17
|
-
super().__init__()
|
18
|
-
self.delta_t_supply_fan = float
|
19
|
-
self.outdoor_degf_err_thres = float
|
20
|
-
self.supply_degf_err_thres = float
|
21
|
-
self.ahu_min_oa_dpr = float
|
22
|
-
self.sat_setpoint_col = str
|
23
|
-
self.oat_col = str
|
24
|
-
self.cooling_sig_col = str
|
25
|
-
self.economizer_sig_col = str
|
26
|
-
self.troubleshoot_mode = bool # default should be False
|
27
|
-
self.rolling_window_size = int
|
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
|
-
|
43
|
-
self.set_attributes(dict_)
|
44
|
-
|
45
|
-
# Set required columns specific to this fault condition
|
46
|
-
self.required_columns = [
|
47
|
-
self.sat_setpoint_col,
|
48
|
-
self.oat_col,
|
49
|
-
self.cooling_sig_col,
|
50
|
-
self.economizer_sig_col,
|
51
|
-
]
|
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
|
-
|
70
|
-
def get_required_columns(self) -> str:
|
71
|
-
"""Returns a string representation of the required columns."""
|
72
|
-
return (
|
73
|
-
f"{self.equation_string}"
|
74
|
-
f"{self.description_string}"
|
75
|
-
f"{self.required_column_description}"
|
76
|
-
f"{self.mapped_columns}"
|
77
|
-
)
|
78
|
-
|
79
|
-
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
80
|
-
try:
|
81
|
-
# Ensure all required columns are present
|
82
|
-
self.check_required_columns(df)
|
83
|
-
|
84
|
-
if self.troubleshoot_mode:
|
85
|
-
self.troubleshoot_cols(df)
|
86
|
-
|
87
|
-
# Check analog outputs [data with units of %] are floats only
|
88
|
-
columns_to_check = [
|
89
|
-
self.economizer_sig_col,
|
90
|
-
self.cooling_sig_col,
|
91
|
-
]
|
92
|
-
self.check_analog_pct(df, columns_to_check)
|
93
|
-
|
94
|
-
# Create helper columns
|
95
|
-
df["oat_minus_oaterror"] = df[self.oat_col] - self.outdoor_degf_err_thres
|
96
|
-
df["satsp_delta_saterr"] = (
|
97
|
-
df[self.sat_setpoint_col]
|
98
|
-
- self.delta_t_supply_fan
|
99
|
-
+ self.supply_degf_err_thres
|
100
|
-
)
|
101
|
-
|
102
|
-
df["combined_check"] = (
|
103
|
-
(df["oat_minus_oaterror"] > df["satsp_delta_saterr"])
|
104
|
-
# verify AHU is in OS2 only free cooling mode
|
105
|
-
& (df[self.economizer_sig_col] > self.ahu_min_oa_dpr)
|
106
|
-
& (df[self.cooling_sig_col] < 0.1)
|
107
|
-
)
|
108
|
-
|
109
|
-
# Rolling sum to count consecutive trues
|
110
|
-
rolling_sum = (
|
111
|
-
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
112
|
-
)
|
113
|
-
# Set flag to 1 if rolling sum equals the window size
|
114
|
-
df["fc9_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
115
|
-
|
116
|
-
if self.troubleshoot_mode:
|
117
|
-
print("Troubleshoot mode enabled - not removing helper columns")
|
118
|
-
sys.stdout.flush()
|
119
|
-
del df["oat_minus_oaterror"]
|
120
|
-
del df["satsp_delta_saterr"]
|
121
|
-
del df["combined_check"]
|
122
|
-
|
123
|
-
return df
|
124
|
-
|
125
|
-
except MissingColumnError as e:
|
126
|
-
print(f"Error: {e.message}")
|
127
|
-
sys.stdout.flush()
|
128
|
-
raise e
|
@@ -1,112 +0,0 @@
|
|
1
|
-
import pandas as pd
|
2
|
-
from open_fdd.air_handling_unit.faults.fault_condition import (
|
3
|
-
FaultCondition,
|
4
|
-
MissingColumnError,
|
5
|
-
)
|
6
|
-
import sys
|
7
|
-
|
8
|
-
|
9
|
-
class FaultConditionOne(FaultCondition):
|
10
|
-
"""Class provides the definitions for Fault Condition 1.
|
11
|
-
AHU low duct static pressure fan fault.
|
12
|
-
"""
|
13
|
-
|
14
|
-
def __init__(self, dict_):
|
15
|
-
super().__init__()
|
16
|
-
self.vfd_speed_percent_err_thres = float
|
17
|
-
self.vfd_speed_percent_max = float
|
18
|
-
self.duct_static_inches_err_thres = float
|
19
|
-
self.duct_static_col = str
|
20
|
-
self.supply_vfd_speed_col = str
|
21
|
-
self.duct_static_setpoint_col = str
|
22
|
-
self.troubleshoot_mode = bool # default should be False
|
23
|
-
self.rolling_window_size = int
|
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
|
-
|
32
|
-
self.set_attributes(dict_)
|
33
|
-
|
34
|
-
# Set required columns specific to this fault condition manually
|
35
|
-
self.required_columns = [
|
36
|
-
self.duct_static_col,
|
37
|
-
self.supply_vfd_speed_col,
|
38
|
-
self.duct_static_setpoint_col,
|
39
|
-
]
|
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
|
-
|
58
|
-
def get_required_columns(self) -> str:
|
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
|
-
)
|
66
|
-
|
67
|
-
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
68
|
-
try:
|
69
|
-
# Ensure all required columns are present
|
70
|
-
self.check_required_columns(df)
|
71
|
-
|
72
|
-
if self.troubleshoot_mode:
|
73
|
-
self.troubleshoot_cols(df)
|
74
|
-
|
75
|
-
# Check analog outputs [data with units of %] are floats only
|
76
|
-
columns_to_check = [self.supply_vfd_speed_col]
|
77
|
-
self.check_analog_pct(df, columns_to_check)
|
78
|
-
|
79
|
-
df["static_check_"] = (
|
80
|
-
df[self.duct_static_col]
|
81
|
-
< df[self.duct_static_setpoint_col] - self.duct_static_inches_err_thres
|
82
|
-
)
|
83
|
-
df["fan_check_"] = (
|
84
|
-
df[self.supply_vfd_speed_col]
|
85
|
-
>= self.vfd_speed_percent_max - self.vfd_speed_percent_err_thres
|
86
|
-
)
|
87
|
-
|
88
|
-
# Combined condition check
|
89
|
-
df["combined_check"] = df["static_check_"] & df["fan_check_"]
|
90
|
-
|
91
|
-
# Rolling sum to count consecutive trues
|
92
|
-
rolling_sum = (
|
93
|
-
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
94
|
-
)
|
95
|
-
# Set flag to 1 if rolling sum equals the window size
|
96
|
-
df["fc1_flag"] = (rolling_sum == self.rolling_window_size).astype(int)
|
97
|
-
|
98
|
-
if self.troubleshoot_mode:
|
99
|
-
print("Troubleshoot mode enabled - not removing helper columns")
|
100
|
-
sys.stdout.flush()
|
101
|
-
|
102
|
-
# Optionally remove temporary columns
|
103
|
-
df.drop(
|
104
|
-
columns=["static_check_", "fan_check_", "combined_check"], inplace=True
|
105
|
-
)
|
106
|
-
|
107
|
-
return df
|
108
|
-
|
109
|
-
except MissingColumnError as e:
|
110
|
-
print(f"Error: {e.message}")
|
111
|
-
sys.stdout.flush()
|
112
|
-
raise e
|
@@ -1,114 +0,0 @@
|
|
1
|
-
import pandas as pd
|
2
|
-
from open_fdd.air_handling_unit.faults.fault_condition import (
|
3
|
-
FaultCondition,
|
4
|
-
MissingColumnError,
|
5
|
-
)
|
6
|
-
import sys
|
7
|
-
|
8
|
-
|
9
|
-
class FaultConditionSeven(FaultCondition):
|
10
|
-
"""Class provides the definitions for Fault Condition 7.
|
11
|
-
Very similar to FC 13 but uses heating valve.
|
12
|
-
Supply air temperature too low in full heating.
|
13
|
-
"""
|
14
|
-
|
15
|
-
def __init__(self, dict_):
|
16
|
-
super().__init__()
|
17
|
-
self.supply_degf_err_thres = float
|
18
|
-
self.sat_col = str
|
19
|
-
self.sat_setpoint_col = str
|
20
|
-
self.heating_sig_col = str
|
21
|
-
self.supply_vfd_speed_col = str
|
22
|
-
self.troubleshoot_mode = bool # default to False
|
23
|
-
self.rolling_window_size = int
|
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
|
-
|
39
|
-
self.set_attributes(dict_)
|
40
|
-
|
41
|
-
# Set required columns specific to this fault condition
|
42
|
-
self.required_columns = [
|
43
|
-
self.sat_col,
|
44
|
-
self.sat_setpoint_col,
|
45
|
-
self.heating_sig_col,
|
46
|
-
self.supply_vfd_speed_col,
|
47
|
-
]
|
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
|
-
|
66
|
-
def get_required_columns(self) -> str:
|
67
|
-
"""Returns a string representation of the required columns."""
|
68
|
-
return (
|
69
|
-
f"{self.equation_string}"
|
70
|
-
f"{self.description_string}"
|
71
|
-
f"{self.required_column_description}"
|
72
|
-
f"{self.mapped_columns}"
|
73
|
-
)
|
74
|
-
|
75
|
-
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
76
|
-
try:
|
77
|
-
# Ensure all required columns are present
|
78
|
-
self.check_required_columns(df)
|
79
|
-
|
80
|
-
if self.troubleshoot_mode:
|
81
|
-
self.troubleshoot_cols(df)
|
82
|
-
|
83
|
-
# Check analog outputs [data with units of %] are floats only
|
84
|
-
columns_to_check = [self.supply_vfd_speed_col, self.heating_sig_col]
|
85
|
-
self.check_analog_pct(df, columns_to_check)
|
86
|
-
|
87
|
-
# Fault condition-specific checks / flags
|
88
|
-
df["sat_check"] = df[self.sat_setpoint_col] - self.supply_degf_err_thres
|
89
|
-
|
90
|
-
df["combined_check"] = (
|
91
|
-
(df[self.sat_col] < df["sat_check"])
|
92
|
-
& (df[self.heating_sig_col] > 0.9)
|
93
|
-
& (df[self.supply_vfd_speed_col] > 0)
|
94
|
-
)
|
95
|
-
|
96
|
-
# Rolling sum to count consecutive trues
|
97
|
-
rolling_sum = (
|
98
|
-
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
99
|
-
)
|
100
|
-
# Set flag to 1 if rolling sum equals the window size
|
101
|
-
df["fc7_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
102
|
-
|
103
|
-
if self.troubleshoot_mode:
|
104
|
-
print("Troubleshoot mode enabled - not removing helper columns")
|
105
|
-
sys.stdout.flush()
|
106
|
-
del df["sat_check"]
|
107
|
-
del df["combined_check"]
|
108
|
-
|
109
|
-
return df
|
110
|
-
|
111
|
-
except MissingColumnError as e:
|
112
|
-
print(f"Error: {e.message}")
|
113
|
-
sys.stdout.flush()
|
114
|
-
raise e
|
@@ -1,181 +0,0 @@
|
|
1
|
-
import pandas as pd
|
2
|
-
import operator
|
3
|
-
from open_fdd.air_handling_unit.faults.fault_condition import (
|
4
|
-
FaultCondition,
|
5
|
-
MissingColumnError,
|
6
|
-
)
|
7
|
-
import sys
|
8
|
-
|
9
|
-
|
10
|
-
class FaultConditionSix(FaultCondition):
|
11
|
-
"""Class provides the definitions for Fault Condition 6.
|
12
|
-
|
13
|
-
This fault related to knowing the design air flow for
|
14
|
-
ventilation AHU_MIN_CFM_DESIGN which comes from the
|
15
|
-
design mech engineered records where then the fault
|
16
|
-
tries to calculate that based on totalized measured
|
17
|
-
AHU air flow and outside air fraction calc from
|
18
|
-
AHU temp sensors. The fault could flag issues where
|
19
|
-
flow stations are either not in calibration, temp
|
20
|
-
sensors used in the OA frac calc, or possibly the AHU
|
21
|
-
not bringing in design air flow when not operating in
|
22
|
-
economizer free cooling modes.
|
23
|
-
"""
|
24
|
-
|
25
|
-
def __init__(self, dict_):
|
26
|
-
super().__init__()
|
27
|
-
self.airflow_err_thres = float
|
28
|
-
self.ahu_min_oa_cfm_design = float
|
29
|
-
self.outdoor_degf_err_thres = float
|
30
|
-
self.return_degf_err_thres = float
|
31
|
-
self.oat_rat_delta_min = float
|
32
|
-
self.ahu_min_oa_dpr = float
|
33
|
-
self.supply_fan_air_volume_col = str
|
34
|
-
self.mat_col = str
|
35
|
-
self.oat_col = str
|
36
|
-
self.rat_col = str
|
37
|
-
self.supply_vfd_speed_col = str
|
38
|
-
self.economizer_sig_col = str
|
39
|
-
self.heating_sig_col = str
|
40
|
-
self.cooling_sig_col = str
|
41
|
-
self.troubleshoot_mode = bool # default should be False
|
42
|
-
self.rolling_window_size = int
|
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
|
-
|
59
|
-
self.set_attributes(dict_)
|
60
|
-
|
61
|
-
# Set required columns specific to this fault condition
|
62
|
-
self.required_columns = [
|
63
|
-
self.supply_fan_air_volume_col,
|
64
|
-
self.mat_col,
|
65
|
-
self.oat_col,
|
66
|
-
self.rat_col,
|
67
|
-
self.supply_vfd_speed_col,
|
68
|
-
self.economizer_sig_col,
|
69
|
-
self.heating_sig_col,
|
70
|
-
self.cooling_sig_col,
|
71
|
-
]
|
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
|
-
|
90
|
-
def get_required_columns(self) -> str:
|
91
|
-
"""Returns a string representation of the required columns."""
|
92
|
-
return (
|
93
|
-
f"{self.equation_string}"
|
94
|
-
f"{self.description_string}"
|
95
|
-
f"{self.required_column_description}"
|
96
|
-
f"{self.mapped_columns}"
|
97
|
-
)
|
98
|
-
|
99
|
-
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
100
|
-
try:
|
101
|
-
# Ensure all required columns are present
|
102
|
-
self.check_required_columns(df)
|
103
|
-
|
104
|
-
if self.troubleshoot_mode:
|
105
|
-
self.troubleshoot_cols(df)
|
106
|
-
|
107
|
-
# Check analog outputs [data with units of %] are floats only
|
108
|
-
columns_to_check = [
|
109
|
-
self.supply_vfd_speed_col,
|
110
|
-
self.economizer_sig_col,
|
111
|
-
self.heating_sig_col,
|
112
|
-
self.cooling_sig_col,
|
113
|
-
]
|
114
|
-
|
115
|
-
for col in columns_to_check:
|
116
|
-
self.check_analog_pct(df, [col])
|
117
|
-
|
118
|
-
# Create helper columns
|
119
|
-
df["rat_minus_oat"] = abs(df[self.rat_col] - df[self.oat_col])
|
120
|
-
df["percent_oa_calc"] = (df[self.mat_col] - df[self.rat_col]) / (
|
121
|
-
df[self.oat_col] - df[self.rat_col]
|
122
|
-
)
|
123
|
-
|
124
|
-
# Weed out any negative values
|
125
|
-
df["percent_oa_calc"] = df["percent_oa_calc"].apply(
|
126
|
-
lambda x: x if x > 0 else 0
|
127
|
-
)
|
128
|
-
|
129
|
-
df["perc_OAmin"] = (
|
130
|
-
self.ahu_min_oa_cfm_design / df[self.supply_fan_air_volume_col]
|
131
|
-
)
|
132
|
-
|
133
|
-
df["percent_oa_calc_minus_perc_OAmin"] = abs(
|
134
|
-
df["percent_oa_calc"] - df["perc_OAmin"]
|
135
|
-
)
|
136
|
-
|
137
|
-
df["combined_check"] = operator.or_(
|
138
|
-
# OS 1 htg mode
|
139
|
-
(
|
140
|
-
(df["rat_minus_oat"] >= self.oat_rat_delta_min)
|
141
|
-
& (df["percent_oa_calc_minus_perc_OAmin"] > self.airflow_err_thres)
|
142
|
-
)
|
143
|
-
# Verify AHU is running in OS 1 htg mode in min OA
|
144
|
-
& (
|
145
|
-
(df[self.heating_sig_col] > 0.0)
|
146
|
-
& (df[self.supply_vfd_speed_col] > 0.0)
|
147
|
-
), # OR
|
148
|
-
# OS 4 mech clg mode
|
149
|
-
(
|
150
|
-
(df["rat_minus_oat"] >= self.oat_rat_delta_min)
|
151
|
-
& (df["percent_oa_calc_minus_perc_OAmin"] > self.airflow_err_thres)
|
152
|
-
)
|
153
|
-
# Verify AHU is running in OS 4 clg mode in min OA
|
154
|
-
& (df[self.heating_sig_col] == 0.0)
|
155
|
-
& (df[self.cooling_sig_col] > 0.0)
|
156
|
-
& (df[self.supply_vfd_speed_col] > 0.0)
|
157
|
-
& (df[self.economizer_sig_col] == self.ahu_min_oa_dpr),
|
158
|
-
)
|
159
|
-
|
160
|
-
# Rolling sum to count consecutive trues
|
161
|
-
rolling_sum = (
|
162
|
-
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
163
|
-
)
|
164
|
-
# Set flag to 1 if rolling sum equals the window size
|
165
|
-
df["fc6_flag"] = (rolling_sum == self.rolling_window_size).astype(int)
|
166
|
-
|
167
|
-
if self.troubleshoot_mode:
|
168
|
-
print("Troubleshoot mode enabled - not removing helper columns")
|
169
|
-
sys.stdout.flush()
|
170
|
-
del df["rat_minus_oat"]
|
171
|
-
del df["percent_oa_calc"]
|
172
|
-
del df["perc_OAmin"]
|
173
|
-
del df["percent_oa_calc_minus_perc_OAmin"]
|
174
|
-
del df["combined_check"]
|
175
|
-
|
176
|
-
return df
|
177
|
-
|
178
|
-
except MissingColumnError as e:
|
179
|
-
print(f"Error: {e.message}")
|
180
|
-
sys.stdout.flush()
|
181
|
-
raise e
|
@@ -1,123 +0,0 @@
|
|
1
|
-
import pandas as pd
|
2
|
-
import numpy as np
|
3
|
-
from open_fdd.air_handling_unit.faults.fault_condition import (
|
4
|
-
FaultCondition,
|
5
|
-
MissingColumnError,
|
6
|
-
)
|
7
|
-
import sys
|
8
|
-
|
9
|
-
|
10
|
-
class FaultConditionTen(FaultCondition):
|
11
|
-
"""Class provides the definitions for Fault Condition 10.
|
12
|
-
Outdoor air temperature and mix air temperature should
|
13
|
-
be approx equal in economizer plus mech cooling mode.
|
14
|
-
"""
|
15
|
-
|
16
|
-
def __init__(self, dict_):
|
17
|
-
super().__init__()
|
18
|
-
self.outdoor_degf_err_thres = float
|
19
|
-
self.mix_degf_err_thres = float
|
20
|
-
self.oat_col = str
|
21
|
-
self.mat_col = str
|
22
|
-
self.cooling_sig_col = str
|
23
|
-
self.economizer_sig_col = str
|
24
|
-
self.troubleshoot_mode = bool # default False,
|
25
|
-
self.rolling_window_size = int
|
26
|
-
|
27
|
-
self.equation_string = (
|
28
|
-
"fc10_flag = 1 if |OAT - MAT| > √(εOAT² + εMAT²) in "
|
29
|
-
"economizer + mech cooling mode for N consecutive values else 0 \n"
|
30
|
-
)
|
31
|
-
self.description_string = (
|
32
|
-
"Fault Condition 10: Outdoor air temperature and mixed air temperature "
|
33
|
-
"should be approximately equal in economizer plus mechanical cooling mode \n"
|
34
|
-
)
|
35
|
-
self.required_column_description = (
|
36
|
-
"Required inputs are the outside air temperature, mixed air temperature, "
|
37
|
-
"cooling signal, and economizer signal \n"
|
38
|
-
)
|
39
|
-
self.error_string = f"One or more required columns are missing or None \n"
|
40
|
-
|
41
|
-
self.set_attributes(dict_)
|
42
|
-
|
43
|
-
# Set required columns specific to this fault condition
|
44
|
-
self.required_columns = [
|
45
|
-
self.oat_col,
|
46
|
-
self.mat_col,
|
47
|
-
self.cooling_sig_col,
|
48
|
-
self.economizer_sig_col,
|
49
|
-
]
|
50
|
-
|
51
|
-
# Check if any of the required columns are None
|
52
|
-
if any(col is None for col in self.required_columns):
|
53
|
-
raise MissingColumnError(
|
54
|
-
f"{self.error_string}"
|
55
|
-
f"{self.equation_string}"
|
56
|
-
f"{self.description_string}"
|
57
|
-
f"{self.required_column_description}"
|
58
|
-
f"{self.required_columns}"
|
59
|
-
)
|
60
|
-
|
61
|
-
# Ensure all required columns are strings
|
62
|
-
self.required_columns = [str(col) for col in self.required_columns]
|
63
|
-
|
64
|
-
self.mapped_columns = (
|
65
|
-
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
66
|
-
)
|
67
|
-
|
68
|
-
def get_required_columns(self) -> str:
|
69
|
-
"""Returns a string representation of the required columns."""
|
70
|
-
return (
|
71
|
-
f"{self.equation_string}"
|
72
|
-
f"{self.description_string}"
|
73
|
-
f"{self.required_column_description}"
|
74
|
-
f"{self.mapped_columns}"
|
75
|
-
)
|
76
|
-
|
77
|
-
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
78
|
-
try:
|
79
|
-
# Ensure all required columns are present
|
80
|
-
self.check_required_columns(df)
|
81
|
-
|
82
|
-
if self.troubleshoot_mode:
|
83
|
-
self.troubleshoot_cols(df)
|
84
|
-
|
85
|
-
# Check analog outputs [data with units of %] are floats only
|
86
|
-
columns_to_check = [
|
87
|
-
self.economizer_sig_col,
|
88
|
-
self.cooling_sig_col,
|
89
|
-
]
|
90
|
-
self.check_analog_pct(df, columns_to_check)
|
91
|
-
|
92
|
-
df["abs_mat_minus_oat"] = abs(df[self.mat_col] - df[self.oat_col])
|
93
|
-
df["mat_oat_sqrted"] = np.sqrt(
|
94
|
-
self.mix_degf_err_thres**2 + self.outdoor_degf_err_thres**2
|
95
|
-
)
|
96
|
-
|
97
|
-
df["combined_check"] = (
|
98
|
-
(df["abs_mat_minus_oat"] > df["mat_oat_sqrted"])
|
99
|
-
# verify AHU is running in OS 3 clg mode in min OA
|
100
|
-
& (df[self.cooling_sig_col] > 0.01)
|
101
|
-
& (df[self.economizer_sig_col] > 0.9)
|
102
|
-
)
|
103
|
-
|
104
|
-
# Rolling sum to count consecutive trues
|
105
|
-
rolling_sum = (
|
106
|
-
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
107
|
-
)
|
108
|
-
# Set flag to 1 if rolling sum equals the window size
|
109
|
-
df["fc10_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
110
|
-
|
111
|
-
if self.troubleshoot_mode:
|
112
|
-
print("Troubleshoot mode enabled - not removing helper columns")
|
113
|
-
sys.stdout.flush()
|
114
|
-
del df["abs_mat_minus_oat"]
|
115
|
-
del df["mat_oat_sqrted"]
|
116
|
-
del df["combined_check"]
|
117
|
-
|
118
|
-
return df
|
119
|
-
|
120
|
-
except MissingColumnError as e:
|
121
|
-
print(f"Error: {e.message}")
|
122
|
-
sys.stdout.flush()
|
123
|
-
raise e
|