open-fdd 0.1.1__py3-none-any.whl → 0.1.3__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/fault_condition.py +26 -8
- open_fdd/air_handling_unit/faults/fault_condition_eight.py +61 -37
- open_fdd/air_handling_unit/faults/fault_condition_eleven.py +59 -37
- open_fdd/air_handling_unit/faults/fault_condition_fifteen.py +77 -51
- open_fdd/air_handling_unit/faults/fault_condition_five.py +60 -41
- open_fdd/air_handling_unit/faults/fault_condition_four.py +108 -65
- open_fdd/air_handling_unit/faults/fault_condition_fourteen.py +71 -44
- open_fdd/air_handling_unit/faults/fault_condition_nine.py +60 -36
- open_fdd/air_handling_unit/faults/fault_condition_one.py +58 -37
- open_fdd/air_handling_unit/faults/fault_condition_seven.py +55 -32
- open_fdd/air_handling_unit/faults/fault_condition_six.py +100 -76
- open_fdd/air_handling_unit/faults/fault_condition_ten.py +62 -37
- open_fdd/air_handling_unit/faults/fault_condition_thirteen.py +61 -36
- open_fdd/air_handling_unit/faults/fault_condition_three.py +58 -33
- open_fdd/air_handling_unit/faults/fault_condition_twelve.py +63 -39
- open_fdd/air_handling_unit/faults/fault_condition_two.py +58 -36
- open_fdd/air_handling_unit/faults/helper_utils.py +294 -64
- 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 +175 -0
- 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 +47 -0
- open_fdd/air_handling_unit/reports/report_fc7.py +3 -1
- open_fdd/tests/ahu/test_ahu_fc1.py +17 -0
- open_fdd/tests/ahu/test_ahu_fc4.py +127 -199
- {open_fdd-0.1.1.dist-info → open_fdd-0.1.3.dist-info}/METADATA +35 -5
- {open_fdd-0.1.1.dist-info → open_fdd-0.1.3.dist-info}/RECORD +48 -25
- {open_fdd-0.1.1.dist-info → open_fdd-0.1.3.dist-info}/LICENSE +0 -0
- {open_fdd-0.1.1.dist-info → open_fdd-0.1.3.dist-info}/WHEEL +0 -0
- {open_fdd-0.1.1.dist-info → open_fdd-0.1.3.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,8 @@
|
|
1
1
|
import pandas as pd
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
from open_fdd.air_handling_unit.faults.fault_condition import (
|
3
|
+
FaultCondition,
|
4
|
+
MissingColumnError,
|
5
|
+
)
|
5
6
|
import sys
|
6
7
|
|
7
8
|
|
@@ -12,6 +13,7 @@ class FaultConditionSeven(FaultCondition):
|
|
12
13
|
"""
|
13
14
|
|
14
15
|
def __init__(self, dict_):
|
16
|
+
super().__init__()
|
15
17
|
self.supply_degf_err_thres = float
|
16
18
|
self.sat_col = str
|
17
19
|
self.sat_setpoint_col = str
|
@@ -22,34 +24,55 @@ class FaultConditionSeven(FaultCondition):
|
|
22
24
|
|
23
25
|
self.set_attributes(dict_)
|
24
26
|
|
27
|
+
# Set required columns specific to this fault condition
|
28
|
+
self.required_columns = [
|
29
|
+
self.sat_col,
|
30
|
+
self.sat_setpoint_col,
|
31
|
+
self.heating_sig_col,
|
32
|
+
self.supply_vfd_speed_col,
|
33
|
+
]
|
34
|
+
|
35
|
+
def get_required_columns(self) -> str:
|
36
|
+
"""Returns a string representation of the required columns."""
|
37
|
+
return f"Required columns for FaultConditionSeven: {', '.join(self.required_columns)}"
|
38
|
+
|
25
39
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
& (df[self.supply_vfd_speed_col] > 0)
|
40
|
-
)
|
41
|
-
|
42
|
-
# Rolling sum to count consecutive trues
|
43
|
-
rolling_sum = (
|
44
|
-
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
45
|
-
)
|
46
|
-
# Set flag to 1 if rolling sum equals the window size
|
47
|
-
df["fc7_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
48
|
-
|
49
|
-
if self.troubleshoot_mode:
|
50
|
-
print("Troubleshoot mode enabled - not removing helper columns")
|
51
|
-
sys.stdout.flush()
|
52
|
-
del df["sat_check"]
|
53
|
-
del df["combined_check"]
|
40
|
+
try:
|
41
|
+
# Ensure all required columns are present
|
42
|
+
self.check_required_columns(df)
|
43
|
+
|
44
|
+
if self.troubleshoot_mode:
|
45
|
+
self.troubleshoot_cols(df)
|
46
|
+
|
47
|
+
# Check analog outputs [data with units of %] are floats only
|
48
|
+
columns_to_check = [self.supply_vfd_speed_col, self.heating_sig_col]
|
49
|
+
self.check_analog_pct(df, columns_to_check)
|
50
|
+
|
51
|
+
# Fault condition-specific checks / flags
|
52
|
+
df["sat_check"] = df[self.sat_setpoint_col] - self.supply_degf_err_thres
|
54
53
|
|
55
|
-
|
54
|
+
df["combined_check"] = (
|
55
|
+
(df[self.sat_col] < df["sat_check"])
|
56
|
+
& (df[self.heating_sig_col] > 0.9)
|
57
|
+
& (df[self.supply_vfd_speed_col] > 0)
|
58
|
+
)
|
59
|
+
|
60
|
+
# Rolling sum to count consecutive trues
|
61
|
+
rolling_sum = (
|
62
|
+
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
63
|
+
)
|
64
|
+
# Set flag to 1 if rolling sum equals the window size
|
65
|
+
df["fc7_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
66
|
+
|
67
|
+
if self.troubleshoot_mode:
|
68
|
+
print("Troubleshoot mode enabled - not removing helper columns")
|
69
|
+
sys.stdout.flush()
|
70
|
+
del df["sat_check"]
|
71
|
+
del df["combined_check"]
|
72
|
+
|
73
|
+
return df
|
74
|
+
|
75
|
+
except MissingColumnError as e:
|
76
|
+
print(f"Error: {e.message}")
|
77
|
+
sys.stdout.flush()
|
78
|
+
raise e # Re-raise the exception so it can be caught by pytest
|
@@ -1,33 +1,29 @@
|
|
1
1
|
import pandas as pd
|
2
|
-
import pandas.api.types as pdtypes
|
3
|
-
from open_fdd.air_handling_unit.faults.fault_condition import FaultCondition
|
4
|
-
from open_fdd.air_handling_unit.faults.helper_utils import HelperUtils
|
5
2
|
import operator
|
3
|
+
from open_fdd.air_handling_unit.faults.fault_condition import (
|
4
|
+
FaultCondition,
|
5
|
+
MissingColumnError,
|
6
|
+
)
|
6
7
|
import sys
|
7
8
|
|
8
9
|
|
9
10
|
class FaultConditionSix(FaultCondition):
|
10
11
|
"""Class provides the definitions for Fault Condition 6.
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
verifying flow sensor and temp sensor precisions from
|
23
|
-
3rd party sensing tools.
|
24
|
-
|
25
|
-
this fault is confusing if you want to play around
|
26
|
-
in py code sandbox try this:
|
27
|
-
https://gist.github.com/bbartling/e0fb8427b1e0d148a06e3f09121ed5dc#file-fc6-py
|
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.
|
28
23
|
"""
|
29
24
|
|
30
25
|
def __init__(self, dict_):
|
26
|
+
super().__init__()
|
31
27
|
self.airflow_err_thres = float
|
32
28
|
self.ahu_min_oa_cfm_design = float
|
33
29
|
self.outdoor_degf_err_thres = float
|
@@ -47,74 +43,102 @@ class FaultConditionSix(FaultCondition):
|
|
47
43
|
|
48
44
|
self.set_attributes(dict_)
|
49
45
|
|
50
|
-
|
51
|
-
|
52
|
-
self.
|
53
|
-
|
54
|
-
|
55
|
-
|
46
|
+
# Set required columns specific to this fault condition
|
47
|
+
self.required_columns = [
|
48
|
+
self.supply_fan_air_volume_col,
|
49
|
+
self.mat_col,
|
50
|
+
self.oat_col,
|
51
|
+
self.rat_col,
|
56
52
|
self.supply_vfd_speed_col,
|
57
53
|
self.economizer_sig_col,
|
58
54
|
self.heating_sig_col,
|
59
55
|
self.cooling_sig_col,
|
60
56
|
]
|
61
57
|
|
62
|
-
|
63
|
-
|
58
|
+
def get_required_columns(self) -> str:
|
59
|
+
"""Returns a string representation of the required columns."""
|
60
|
+
return f"Required columns for FaultConditionSix: {', '.join(self.required_columns)}"
|
64
61
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
62
|
+
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
63
|
+
try:
|
64
|
+
# Ensure all required columns are present
|
65
|
+
self.check_required_columns(df)
|
66
|
+
|
67
|
+
if self.troubleshoot_mode:
|
68
|
+
self.troubleshoot_cols(df)
|
69
|
+
|
70
|
+
# Check analog outputs [data with units of %] are floats only
|
71
|
+
columns_to_check = [
|
72
|
+
self.supply_vfd_speed_col,
|
73
|
+
self.economizer_sig_col,
|
74
|
+
self.heating_sig_col,
|
75
|
+
self.cooling_sig_col,
|
76
|
+
]
|
77
|
+
|
78
|
+
for col in columns_to_check:
|
79
|
+
self.check_analog_pct(df, [col])
|
80
|
+
|
81
|
+
# Create helper columns
|
82
|
+
df["rat_minus_oat"] = abs(df[self.rat_col] - df[self.oat_col])
|
83
|
+
df["percent_oa_calc"] = (df[self.mat_col] - df[self.rat_col]) / (
|
84
|
+
df[self.oat_col] - df[self.rat_col]
|
85
|
+
)
|
70
86
|
|
71
|
-
|
72
|
-
|
87
|
+
# Weed out any negative values
|
88
|
+
df["percent_oa_calc"] = df["percent_oa_calc"].apply(
|
89
|
+
lambda x: x if x > 0 else 0
|
90
|
+
)
|
73
91
|
|
74
|
-
|
75
|
-
|
76
|
-
|
92
|
+
df["perc_OAmin"] = (
|
93
|
+
self.ahu_min_oa_cfm_design / df[self.supply_fan_air_volume_col]
|
94
|
+
)
|
77
95
|
|
78
|
-
|
79
|
-
|
80
|
-
|
96
|
+
df["percent_oa_calc_minus_perc_OAmin"] = abs(
|
97
|
+
df["percent_oa_calc"] - df["perc_OAmin"]
|
98
|
+
)
|
81
99
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
100
|
+
df["combined_check"] = operator.or_(
|
101
|
+
# OS 1 htg mode
|
102
|
+
(
|
103
|
+
(df["rat_minus_oat"] >= self.oat_rat_delta_min)
|
104
|
+
& (df["percent_oa_calc_minus_perc_OAmin"] > self.airflow_err_thres)
|
105
|
+
)
|
106
|
+
# Verify AHU is running in OS 1 htg mode in min OA
|
107
|
+
& (
|
108
|
+
(df[self.heating_sig_col] > 0.0)
|
109
|
+
& (df[self.supply_vfd_speed_col] > 0.0)
|
110
|
+
), # OR
|
111
|
+
# OS 4 mech clg mode
|
112
|
+
(
|
113
|
+
(df["rat_minus_oat"] >= self.oat_rat_delta_min)
|
114
|
+
& (df["percent_oa_calc_minus_perc_OAmin"] > self.airflow_err_thres)
|
115
|
+
)
|
116
|
+
# Verify AHU is running in OS 4 clg mode in min OA
|
117
|
+
& (df[self.heating_sig_col] == 0.0)
|
118
|
+
& (df[self.cooling_sig_col] > 0.0)
|
119
|
+
& (df[self.supply_vfd_speed_col] > 0.0)
|
120
|
+
& (df[self.economizer_sig_col] == self.ahu_min_oa_dpr),
|
87
121
|
)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
# OS 4 mech clg mode
|
93
|
-
(
|
94
|
-
(df["rat_minus_oat"] >= self.oat_rat_delta_min)
|
95
|
-
& (df["percent_oa_calc_minus_perc_OAmin"] > self.airflow_err_thres)
|
122
|
+
|
123
|
+
# Rolling sum to count consecutive trues
|
124
|
+
rolling_sum = (
|
125
|
+
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
96
126
|
)
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
print("
|
127
|
+
# Set flag to 1 if rolling sum equals the window size
|
128
|
+
df["fc6_flag"] = (rolling_sum == self.rolling_window_size).astype(int)
|
129
|
+
|
130
|
+
if self.troubleshoot_mode:
|
131
|
+
print("Troubleshoot mode enabled - not removing helper columns")
|
132
|
+
sys.stdout.flush()
|
133
|
+
del df["rat_minus_oat"]
|
134
|
+
del df["percent_oa_calc"]
|
135
|
+
del df["perc_OAmin"]
|
136
|
+
del df["percent_oa_calc_minus_perc_OAmin"]
|
137
|
+
del df["combined_check"]
|
138
|
+
|
139
|
+
return df
|
140
|
+
|
141
|
+
except MissingColumnError as e:
|
142
|
+
print(f"Error: {e.message}")
|
113
143
|
sys.stdout.flush()
|
114
|
-
|
115
|
-
del df["percent_oa_calc"]
|
116
|
-
del df["perc_OAmin"]
|
117
|
-
del df["percent_oa_calc_minus_perc_OAmin"]
|
118
|
-
del df["combined_check"]
|
119
|
-
|
120
|
-
return df
|
144
|
+
raise e # Re-raise the exception so it can be caught by pytest
|
@@ -1,7 +1,9 @@
|
|
1
1
|
import pandas as pd
|
2
2
|
import numpy as np
|
3
|
-
from open_fdd.air_handling_unit.faults.fault_condition import
|
4
|
-
|
3
|
+
from open_fdd.air_handling_unit.faults.fault_condition import (
|
4
|
+
FaultCondition,
|
5
|
+
MissingColumnError,
|
6
|
+
)
|
5
7
|
import sys
|
6
8
|
|
7
9
|
|
@@ -12,6 +14,7 @@ class FaultConditionTen(FaultCondition):
|
|
12
14
|
"""
|
13
15
|
|
14
16
|
def __init__(self, dict_):
|
17
|
+
super().__init__()
|
15
18
|
self.outdoor_degf_err_thres = float
|
16
19
|
self.mix_degf_err_thres = float
|
17
20
|
self.oat_col = str
|
@@ -23,40 +26,62 @@ class FaultConditionTen(FaultCondition):
|
|
23
26
|
|
24
27
|
self.set_attributes(dict_)
|
25
28
|
|
26
|
-
|
27
|
-
|
28
|
-
self.
|
29
|
-
|
30
|
-
# Check analog outputs [data with units of %] are floats only
|
31
|
-
columns_to_check = [
|
32
|
-
self.economizer_sig_col,
|
29
|
+
# Set required columns specific to this fault condition
|
30
|
+
self.required_columns = [
|
31
|
+
self.oat_col,
|
32
|
+
self.mat_col,
|
33
33
|
self.cooling_sig_col,
|
34
|
+
self.economizer_sig_col,
|
34
35
|
]
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
(df
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
36
|
+
|
37
|
+
def get_required_columns(self) -> str:
|
38
|
+
"""Returns a string representation of the required columns."""
|
39
|
+
return f"Required columns for FaultConditionTen: {', '.join(self.required_columns)}"
|
40
|
+
|
41
|
+
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
42
|
+
try:
|
43
|
+
# Ensure all required columns are present
|
44
|
+
self.check_required_columns(df)
|
45
|
+
|
46
|
+
if self.troubleshoot_mode:
|
47
|
+
self.troubleshoot_cols(df)
|
48
|
+
|
49
|
+
# Check analog outputs [data with units of %] are floats only
|
50
|
+
columns_to_check = [
|
51
|
+
self.economizer_sig_col,
|
52
|
+
self.cooling_sig_col,
|
53
|
+
]
|
54
|
+
self.check_analog_pct(df, columns_to_check)
|
55
|
+
|
56
|
+
df["abs_mat_minus_oat"] = abs(df[self.mat_col] - df[self.oat_col])
|
57
|
+
df["mat_oat_sqrted"] = np.sqrt(
|
58
|
+
self.mix_degf_err_thres**2 + self.outdoor_degf_err_thres**2
|
59
|
+
)
|
60
|
+
|
61
|
+
df["combined_check"] = (
|
62
|
+
(df["abs_mat_minus_oat"] > df["mat_oat_sqrted"])
|
63
|
+
# verify ahu is running in OS 3 clg mode in min OA
|
64
|
+
& (df[self.cooling_sig_col] > 0.01)
|
65
|
+
& (df[self.economizer_sig_col] > 0.9)
|
66
|
+
)
|
67
|
+
|
68
|
+
# Rolling sum to count consecutive trues
|
69
|
+
rolling_sum = (
|
70
|
+
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
71
|
+
)
|
72
|
+
# Set flag to 1 if rolling sum equals the window size
|
73
|
+
df["fc10_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
74
|
+
|
75
|
+
if self.troubleshoot_mode:
|
76
|
+
print("Troubleshoot mode enabled - not removing helper columns")
|
77
|
+
sys.stdout.flush()
|
78
|
+
del df["abs_mat_minus_oat"]
|
79
|
+
del df["mat_oat_sqrted"]
|
80
|
+
del df["combined_check"]
|
81
|
+
|
82
|
+
return df
|
83
|
+
|
84
|
+
except MissingColumnError as e:
|
85
|
+
print(f"Error: {e.message}")
|
86
|
+
sys.stdout.flush()
|
87
|
+
raise e # Re-raise the exception so it can be caught by pytest
|
@@ -1,8 +1,9 @@
|
|
1
1
|
import pandas as pd
|
2
|
-
import numpy as np
|
3
2
|
import operator
|
4
|
-
from open_fdd.air_handling_unit.faults.fault_condition import
|
5
|
-
|
3
|
+
from open_fdd.air_handling_unit.faults.fault_condition import (
|
4
|
+
FaultCondition,
|
5
|
+
MissingColumnError,
|
6
|
+
)
|
6
7
|
import sys
|
7
8
|
|
8
9
|
|
@@ -13,6 +14,7 @@ class FaultConditionThirteen(FaultCondition):
|
|
13
14
|
"""
|
14
15
|
|
15
16
|
def __init__(self, dict_):
|
17
|
+
super().__init__()
|
16
18
|
self.supply_degf_err_thres = float
|
17
19
|
self.ahu_min_oa_dpr = float
|
18
20
|
self.sat_col = str
|
@@ -24,43 +26,66 @@ class FaultConditionThirteen(FaultCondition):
|
|
24
26
|
|
25
27
|
self.set_attributes(dict_)
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
-
self.
|
30
|
-
|
31
|
-
# Check analog outputs [data with units of %] are floats only
|
32
|
-
columns_to_check = [
|
33
|
-
self.economizer_sig_col,
|
29
|
+
# Set required columns specific to this fault condition
|
30
|
+
self.required_columns = [
|
31
|
+
self.sat_col,
|
32
|
+
self.sat_setpoint_col,
|
34
33
|
self.cooling_sig_col,
|
34
|
+
self.economizer_sig_col,
|
35
35
|
]
|
36
|
-
self.check_analog_pct(df, columns_to_check)
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
)
|
37
|
+
def get_required_columns(self) -> str:
|
38
|
+
"""Returns a string representation of the required columns."""
|
39
|
+
return f"Required columns for FaultConditionThirteen: {', '.join(self.required_columns)}"
|
42
40
|
|
43
|
-
|
44
|
-
|
45
|
-
#
|
46
|
-
|
47
|
-
& (df[self.economizer_sig_col] == self.ahu_min_oa_dpr), # OR
|
48
|
-
((df["sat_greater_than_sp_calc"]))
|
49
|
-
# verify ahu is running in OS 3 clg mode in 100 OA
|
50
|
-
& (df[self.cooling_sig_col] > 0.01) & (df[self.economizer_sig_col] > 0.9),
|
51
|
-
)
|
41
|
+
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
42
|
+
try:
|
43
|
+
# Ensure all required columns are present
|
44
|
+
self.check_required_columns(df)
|
52
45
|
|
53
|
-
|
54
|
-
|
55
|
-
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
56
|
-
)
|
57
|
-
# Set flag to 1 if rolling sum equals the window size
|
58
|
-
df["fc13_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
46
|
+
if self.troubleshoot_mode:
|
47
|
+
self.troubleshoot_cols(df)
|
59
48
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
49
|
+
# Check analog outputs [data with units of %] are floats only
|
50
|
+
columns_to_check = [
|
51
|
+
self.economizer_sig_col,
|
52
|
+
self.cooling_sig_col,
|
53
|
+
]
|
54
|
+
self.check_analog_pct(df, columns_to_check)
|
65
55
|
|
66
|
-
|
56
|
+
# Create helper columns
|
57
|
+
df["sat_greater_than_sp_calc"] = (
|
58
|
+
df[self.sat_col]
|
59
|
+
> df[self.sat_setpoint_col] + self.supply_degf_err_thres
|
60
|
+
)
|
61
|
+
|
62
|
+
df["combined_check"] = operator.or_(
|
63
|
+
((df["sat_greater_than_sp_calc"]))
|
64
|
+
# OS4 AHU state clg @ min OA
|
65
|
+
& (df[self.cooling_sig_col] > 0.01)
|
66
|
+
& (df[self.economizer_sig_col] == self.ahu_min_oa_dpr), # OR
|
67
|
+
((df["sat_greater_than_sp_calc"]))
|
68
|
+
# verify ahu is running in OS 3 clg mode in 100 OA
|
69
|
+
& (df[self.cooling_sig_col] > 0.01)
|
70
|
+
& (df[self.economizer_sig_col] > 0.9),
|
71
|
+
)
|
72
|
+
|
73
|
+
# Rolling sum to count consecutive trues
|
74
|
+
rolling_sum = (
|
75
|
+
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
76
|
+
)
|
77
|
+
# Set flag to 1 if rolling sum equals the window size
|
78
|
+
df["fc13_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
79
|
+
|
80
|
+
if self.troubleshoot_mode:
|
81
|
+
print("Troubleshoot mode enabled - not removing helper columns")
|
82
|
+
sys.stdout.flush()
|
83
|
+
del df["sat_greater_than_sp_calc"]
|
84
|
+
del df["combined_check"]
|
85
|
+
|
86
|
+
return df
|
87
|
+
|
88
|
+
except MissingColumnError as e:
|
89
|
+
print(f"Error: {e.message}")
|
90
|
+
sys.stdout.flush()
|
91
|
+
raise e # Re-raise the exception so it can be caught by pytest
|
@@ -1,6 +1,9 @@
|
|
1
1
|
import pandas as pd
|
2
2
|
import numpy as np
|
3
|
-
from open_fdd.air_handling_unit.faults.fault_condition import
|
3
|
+
from open_fdd.air_handling_unit.faults.fault_condition import (
|
4
|
+
FaultCondition,
|
5
|
+
MissingColumnError,
|
6
|
+
)
|
4
7
|
import sys
|
5
8
|
|
6
9
|
|
@@ -10,6 +13,7 @@ class FaultConditionThree(FaultCondition):
|
|
10
13
|
"""
|
11
14
|
|
12
15
|
def __init__(self, dict_):
|
16
|
+
super().__init__()
|
13
17
|
self.mix_degf_err_thres = float
|
14
18
|
self.return_degf_err_thres = float
|
15
19
|
self.outdoor_degf_err_thres = float
|
@@ -22,37 +26,58 @@ class FaultConditionThree(FaultCondition):
|
|
22
26
|
|
23
27
|
self.set_attributes(dict_)
|
24
28
|
|
29
|
+
# Set required columns specific to this fault condition
|
30
|
+
self.required_columns = [
|
31
|
+
self.mat_col,
|
32
|
+
self.rat_col,
|
33
|
+
self.oat_col,
|
34
|
+
self.supply_vfd_speed_col,
|
35
|
+
]
|
36
|
+
|
37
|
+
def get_required_columns(self) -> str:
|
38
|
+
"""Returns a string representation of the required columns."""
|
39
|
+
return f"Required columns for FaultConditionThree: {', '.join(self.required_columns)}"
|
40
|
+
|
25
41
|
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
# Rolling sum to count consecutive trues
|
45
|
-
rolling_sum = (
|
46
|
-
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
47
|
-
)
|
48
|
-
# Set flag to 1 if rolling sum equals the window size
|
49
|
-
df["fc3_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
50
|
-
|
51
|
-
if self.troubleshoot_mode:
|
52
|
-
print("Troubleshoot mode enabled - not removing helper columns")
|
53
|
-
sys.stdout.flush()
|
54
|
-
del df["mat_check"]
|
55
|
-
del df["temp_min_check"]
|
56
|
-
del df["combined_check"]
|
42
|
+
try:
|
43
|
+
# Ensure all required columns are present
|
44
|
+
self.check_required_columns(df)
|
45
|
+
|
46
|
+
if self.troubleshoot_mode:
|
47
|
+
self.troubleshoot_cols(df)
|
48
|
+
|
49
|
+
# Check analog outputs [data with units of %] are floats only
|
50
|
+
columns_to_check = [self.supply_vfd_speed_col]
|
51
|
+
self.check_analog_pct(df, columns_to_check)
|
52
|
+
|
53
|
+
# Fault condition-specific checks / flags
|
54
|
+
df["mat_check"] = df[self.mat_col] - self.mix_degf_err_thres
|
55
|
+
df["temp_min_check"] = np.maximum(
|
56
|
+
df[self.rat_col] + self.return_degf_err_thres,
|
57
|
+
df[self.oat_col] + self.outdoor_degf_err_thres,
|
58
|
+
)
|
57
59
|
|
58
|
-
|
60
|
+
df["combined_check"] = (df["mat_check"] > df["temp_min_check"]) & (
|
61
|
+
df[self.supply_vfd_speed_col] > 0.01
|
62
|
+
)
|
63
|
+
|
64
|
+
# Rolling sum to count consecutive trues
|
65
|
+
rolling_sum = (
|
66
|
+
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
67
|
+
)
|
68
|
+
# Set flag to 1 if rolling sum equals the window size
|
69
|
+
df["fc3_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
70
|
+
|
71
|
+
if self.troubleshoot_mode:
|
72
|
+
print("Troubleshoot mode enabled - not removing helper columns")
|
73
|
+
sys.stdout.flush()
|
74
|
+
del df["mat_check"]
|
75
|
+
del df["temp_min_check"]
|
76
|
+
del df["combined_check"]
|
77
|
+
|
78
|
+
return df
|
79
|
+
|
80
|
+
except MissingColumnError as e:
|
81
|
+
print(f"Error: {e.message}")
|
82
|
+
sys.stdout.flush()
|
83
|
+
raise e # Re-raise the exception so it can be caught by pytest
|