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.
Files changed (63) hide show
  1. open_fdd/air_handling_unit/faults/__init__.py +301 -301
  2. open_fdd/air_handling_unit/reports/__init__.py +988 -0
  3. open_fdd/air_handling_unit/reports/fault_report.py +42 -0
  4. open_fdd/tests/ahu/test_ahu_fc16.py +190 -0
  5. {open_fdd-0.1.4.dist-info → open_fdd-0.1.6.dist-info}/METADATA +21 -12
  6. open_fdd-0.1.6.dist-info/RECORD +31 -0
  7. {open_fdd-0.1.4.dist-info → open_fdd-0.1.6.dist-info}/WHEEL +1 -1
  8. open_fdd/air_handling_unit/faults/fault_condition_eight.py +0 -127
  9. open_fdd/air_handling_unit/faults/fault_condition_eleven.py +0 -126
  10. open_fdd/air_handling_unit/faults/fault_condition_fifteen.py +0 -152
  11. open_fdd/air_handling_unit/faults/fault_condition_five.py +0 -123
  12. open_fdd/air_handling_unit/faults/fault_condition_four.py +0 -168
  13. open_fdd/air_handling_unit/faults/fault_condition_fourteen.py +0 -143
  14. open_fdd/air_handling_unit/faults/fault_condition_nine.py +0 -128
  15. open_fdd/air_handling_unit/faults/fault_condition_one.py +0 -112
  16. open_fdd/air_handling_unit/faults/fault_condition_seven.py +0 -114
  17. open_fdd/air_handling_unit/faults/fault_condition_six.py +0 -181
  18. open_fdd/air_handling_unit/faults/fault_condition_ten.py +0 -123
  19. open_fdd/air_handling_unit/faults/fault_condition_thirteen.py +0 -127
  20. open_fdd/air_handling_unit/faults/fault_condition_three.py +0 -113
  21. open_fdd/air_handling_unit/faults/fault_condition_twelve.py +0 -132
  22. open_fdd/air_handling_unit/faults/fault_condition_two.py +0 -113
  23. open_fdd/air_handling_unit/images/ahu1_fc1_2024-06_1.jpg +0 -0
  24. open_fdd/air_handling_unit/images/ahu1_fc1_2024-06_2.jpg +0 -0
  25. open_fdd/air_handling_unit/images/example1.jpg +0 -0
  26. open_fdd/air_handling_unit/images/example2.jpg +0 -0
  27. open_fdd/air_handling_unit/images/fc10_definition.png +0 -0
  28. open_fdd/air_handling_unit/images/fc11_definition.png +0 -0
  29. open_fdd/air_handling_unit/images/fc12_definition.png +0 -0
  30. open_fdd/air_handling_unit/images/fc13_definition.png +0 -0
  31. open_fdd/air_handling_unit/images/fc1_definition.png +0 -0
  32. open_fdd/air_handling_unit/images/fc1_report_screenshot_all.png +0 -0
  33. open_fdd/air_handling_unit/images/fc2_definition.png +0 -0
  34. open_fdd/air_handling_unit/images/fc3_definition.png +0 -0
  35. open_fdd/air_handling_unit/images/fc4_definition.png +0 -0
  36. open_fdd/air_handling_unit/images/fc5_definition.png +0 -0
  37. open_fdd/air_handling_unit/images/fc6_definition.png +0 -0
  38. open_fdd/air_handling_unit/images/fc7_definition.png +0 -0
  39. open_fdd/air_handling_unit/images/fc8_definition.png +0 -0
  40. open_fdd/air_handling_unit/images/fc9_definition.png +0 -0
  41. open_fdd/air_handling_unit/images/latex_generator.py +0 -175
  42. open_fdd/air_handling_unit/images/params.docx +0 -0
  43. open_fdd/air_handling_unit/images/params.pdf +0 -0
  44. open_fdd/air_handling_unit/images/plot_for_repo.png +0 -0
  45. open_fdd/air_handling_unit/reports/base_report.py +0 -47
  46. open_fdd/air_handling_unit/reports/report_fc1.py +0 -115
  47. open_fdd/air_handling_unit/reports/report_fc10.py +0 -126
  48. open_fdd/air_handling_unit/reports/report_fc11.py +0 -128
  49. open_fdd/air_handling_unit/reports/report_fc12.py +0 -126
  50. open_fdd/air_handling_unit/reports/report_fc13.py +0 -126
  51. open_fdd/air_handling_unit/reports/report_fc14.py +0 -124
  52. open_fdd/air_handling_unit/reports/report_fc15.py +0 -124
  53. open_fdd/air_handling_unit/reports/report_fc2.py +0 -119
  54. open_fdd/air_handling_unit/reports/report_fc3.py +0 -119
  55. open_fdd/air_handling_unit/reports/report_fc4.py +0 -148
  56. open_fdd/air_handling_unit/reports/report_fc5.py +0 -132
  57. open_fdd/air_handling_unit/reports/report_fc6.py +0 -156
  58. open_fdd/air_handling_unit/reports/report_fc7.py +0 -126
  59. open_fdd/air_handling_unit/reports/report_fc8.py +0 -118
  60. open_fdd/air_handling_unit/reports/report_fc9.py +0 -120
  61. open_fdd-0.1.4.dist-info/RECORD +0 -82
  62. {open_fdd-0.1.4.dist-info → open_fdd-0.1.6.dist-info}/LICENSE +0 -0
  63. {open_fdd-0.1.4.dist-info → open_fdd-0.1.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,42 @@
1
+ import matplotlib.pyplot as plt
2
+ import pandas as pd
3
+ import numpy as np
4
+ import sys
5
+
6
+
7
+ class BaseFaultReport:
8
+ def __init__(self, config, fault_col):
9
+ self.config = config
10
+ self.fault_col = fault_col
11
+
12
+ def create_plot(self, df: pd.DataFrame):
13
+ raise NotImplementedError
14
+
15
+ def summarize_fault_times(self, df: pd.DataFrame) -> dict:
16
+ raise NotImplementedError
17
+
18
+ def create_hist_plot(self, df: pd.DataFrame):
19
+ df[f"hour_of_the_day_{self.fault_col}"] = df.index.hour.where(
20
+ df[self.fault_col] == 1
21
+ )
22
+ fig, ax = plt.subplots(tight_layout=True, figsize=(25, 8))
23
+ ax.hist(df[f"hour_of_the_day_{self.fault_col}"].dropna())
24
+ ax.set_xlabel("Hour of the Day")
25
+ ax.set_ylabel("Frequency")
26
+ ax.set_title(f"Hour-Of-Day When Fault Flag {self.fault_col} is TRUE")
27
+ plt.show()
28
+ plt.close()
29
+
30
+ def display_report_in_ipython(self, df: pd.DataFrame):
31
+ summary = self.summarize_fault_times(df)
32
+ for key, value in summary.items():
33
+ formatted_key = key.replace("_", " ")
34
+ print(f"{formatted_key}: {value}")
35
+ sys.stdout.flush()
36
+
37
+ if df[self.fault_col].max() != 0:
38
+ self.create_plot(df)
39
+ self.create_hist_plot(df)
40
+ else:
41
+ print("NO FAULTS FOUND - Skipping time-of-day Histogram plot")
42
+ sys.stdout.flush()
@@ -0,0 +1,190 @@
1
+ import pandas as pd
2
+ import pytest
3
+ from open_fdd.air_handling_unit.faults import FaultConditionSixteen
4
+ from open_fdd.air_handling_unit.faults.fault_condition import (
5
+ InvalidParameterError,
6
+ MissingColumnError,
7
+ )
8
+
9
+ """
10
+ To see print statements in pytest run with:
11
+ $ py -3.12 -m pytest open_fdd/tests/ahu/test_ahu_fc16.py -rP -s
12
+
13
+ ERV effectiveness should be within specified thresholds based on OAT.
14
+ """
15
+
16
+
17
+ # Constants
18
+ TEST_ERV_EFFICIENCY_MIN_HEATING = 0.65
19
+ TEST_ERV_EFFICIENCY_MAX_HEATING = 0.8
20
+ TEST_ERV_EFFICIENCY_MIN_COOLING = 0.45
21
+ TEST_ERV_EFFICIENCY_MAX_COOLING = 0.6
22
+ TEST_OAT_LOW_THRESHOLD = 32.0
23
+ TEST_OAT_HIGH_THRESHOLD = 80.0
24
+ TEST_ERV_DEGF_ERR_THRES = 2.0
25
+ TEST_ERV_OAT_ENTER_COL = "erv_oat_enter"
26
+ TEST_ERV_OAT_LEAVING_COL = "erv_oat_leaving"
27
+ TEST_ERV_EAT_ENTER_COL = "erv_eat_enter"
28
+ TEST_ERV_EAT_LEAVING_COL = "erv_eat_leaving"
29
+ TEST_SUPPLY_VFD_SPEED_COL = "supply_vfd_speed"
30
+ ROLLING_WINDOW_SIZE = 1
31
+
32
+ # Initialize FaultConditionSixteen with a dictionary
33
+ fault_condition_params = {
34
+ "ERV_EFFICIENCY_MIN_HEATING": TEST_ERV_EFFICIENCY_MIN_HEATING,
35
+ "ERV_EFFICIENCY_MAX_HEATING": TEST_ERV_EFFICIENCY_MAX_HEATING,
36
+ "ERV_EFFICIENCY_MIN_COOLING": TEST_ERV_EFFICIENCY_MIN_COOLING,
37
+ "ERV_EFFICIENCY_MAX_COOLING": TEST_ERV_EFFICIENCY_MAX_COOLING,
38
+ "OAT_LOW_THRESHOLD": TEST_OAT_LOW_THRESHOLD,
39
+ "OAT_HIGH_THRESHOLD": TEST_OAT_HIGH_THRESHOLD,
40
+ "ERV_DEGF_ERR_THRES": TEST_ERV_DEGF_ERR_THRES,
41
+ "ERV_OAT_ENTER_COL": TEST_ERV_OAT_ENTER_COL,
42
+ "ERV_OAT_LEAVING_COL": TEST_ERV_OAT_LEAVING_COL,
43
+ "ERV_EAT_ENTER_COL": TEST_ERV_EAT_ENTER_COL,
44
+ "ERV_EAT_LEAVING_COL": TEST_ERV_EAT_LEAVING_COL,
45
+ "SUPPLY_VFD_SPEED_COL": TEST_SUPPLY_VFD_SPEED_COL,
46
+ "TROUBLESHOOT_MODE": False,
47
+ "ROLLING_WINDOW_SIZE": ROLLING_WINDOW_SIZE,
48
+ }
49
+
50
+ fc16 = FaultConditionSixteen(fault_condition_params)
51
+
52
+
53
+ class TestFaultConditionSixteen:
54
+
55
+ def no_fault_htg_df(self) -> pd.DataFrame:
56
+ data = {
57
+ TEST_ERV_OAT_ENTER_COL: [10, 10, 10, 10, 10, 10],
58
+ TEST_ERV_OAT_LEAVING_COL: [50.0, 50.5, 50.8, 50.6, 50.2, 50.4],
59
+ TEST_ERV_EAT_ENTER_COL: [70, 70, 70, 70, 70, 70],
60
+ TEST_ERV_EAT_LEAVING_COL: [60, 60.5, 60.2, 60.4, 60.1, 60.3],
61
+ TEST_SUPPLY_VFD_SPEED_COL: [0.5, 0.6, 0.5, 0.7, 0.5, 0.6],
62
+ }
63
+ return pd.DataFrame(data)
64
+
65
+ def fault_htg_df_low_eff(self) -> pd.DataFrame:
66
+ data = {
67
+ TEST_ERV_OAT_ENTER_COL: [10, 10, 10, 10, 10, 10],
68
+ TEST_ERV_OAT_LEAVING_COL: [20.0, 20.5, 20.8, 20.6, 20.2, 20.4],
69
+ TEST_ERV_EAT_ENTER_COL: [70, 70, 70, 70, 70, 70],
70
+ TEST_ERV_EAT_LEAVING_COL: [60, 60.5, 60.2, 60.4, 60.1, 60.3],
71
+ TEST_SUPPLY_VFD_SPEED_COL: [0.5, 0.6, 0.5, 0.7, 0.5, 0.6],
72
+ }
73
+ return pd.DataFrame(data)
74
+
75
+ def fault_htg_df_high_eff(self) -> pd.DataFrame:
76
+ data = {
77
+ TEST_ERV_OAT_ENTER_COL: [10, 10, 10, 10, 10, 10],
78
+ TEST_ERV_OAT_LEAVING_COL: [90.0, 90.5, 90.8, 90.6, 90.2, 90.4],
79
+ TEST_ERV_EAT_ENTER_COL: [70, 70, 70, 70, 70, 70],
80
+ TEST_ERV_EAT_LEAVING_COL: [60, 60.5, 60.2, 60.4, 60.1, 60.3],
81
+ TEST_SUPPLY_VFD_SPEED_COL: [0.5, 0.6, 0.5, 0.7, 0.5, 0.6],
82
+ }
83
+ return pd.DataFrame(data)
84
+
85
+ def test_no_fault_htg(self):
86
+ results = fc16.apply(self.no_fault_htg_df())
87
+ actual = results["fc16_flag"].sum()
88
+ expected = 0
89
+ message = f"FC16 no_fault_htg actual is {actual} and expected is {expected}"
90
+ assert actual == expected, message
91
+
92
+ def test_fault_htg_low_eff(self):
93
+ results = fc16.apply(self.fault_htg_df_low_eff())
94
+ actual = results["fc16_flag"].sum()
95
+ expected = 6
96
+ message = (
97
+ f"FC16 fault_htg_low_eff actual is {actual} and expected is {expected}"
98
+ )
99
+ assert actual == expected, message
100
+
101
+ def test_fault_htg_high_eff(self):
102
+ results = fc16.apply(self.fault_htg_df_high_eff())
103
+ actual = results["fc16_flag"].sum()
104
+ expected = 6
105
+ message = (
106
+ f"FC16 fault_htg_high_eff actual is {actual} and expected is {expected}"
107
+ )
108
+ assert actual == expected, message
109
+
110
+
111
+ class TestFaultOnInvalidParams:
112
+
113
+ def test_invalid_param_type(self):
114
+ """Test that InvalidParameterError is raised for non-float parameters."""
115
+ with pytest.raises(InvalidParameterError) as excinfo:
116
+ FaultConditionSixteen(
117
+ {
118
+ "ERV_EFFICIENCY_MIN_HEATING": "0.65", # Invalid, should be float
119
+ "ERV_EFFICIENCY_MAX_HEATING": 0.8,
120
+ "ERV_EFFICIENCY_MIN_COOLING": 0.45,
121
+ "ERV_EFFICIENCY_MAX_COOLING": 0.6,
122
+ "OAT_LOW_THRESHOLD": 32.0,
123
+ "OAT_HIGH_THRESHOLD": 80.0,
124
+ "ERV_DEGF_ERR_THRES": 2.0,
125
+ "ERV_OAT_ENTER_COL": TEST_ERV_OAT_ENTER_COL,
126
+ "ERV_OAT_LEAVING_COL": TEST_ERV_OAT_LEAVING_COL,
127
+ "ERV_EAT_ENTER_COL": TEST_ERV_EAT_ENTER_COL,
128
+ "ERV_EAT_LEAVING_COL": TEST_ERV_EAT_LEAVING_COL,
129
+ "SUPPLY_VFD_SPEED_COL": TEST_SUPPLY_VFD_SPEED_COL,
130
+ }
131
+ )
132
+ assert "should be a float" in str(excinfo.value)
133
+
134
+ def test_invalid_efficiency_value(self):
135
+ """Test that InvalidParameterError is raised if efficiency values are out of 0.0 - 1.0 range."""
136
+ with pytest.raises(InvalidParameterError) as excinfo:
137
+ FaultConditionSixteen(
138
+ {
139
+ "ERV_EFFICIENCY_MIN_HEATING": 75.0, # Invalid, should be between 0.0 and 1.0
140
+ "ERV_EFFICIENCY_MAX_HEATING": 0.8,
141
+ "ERV_EFFICIENCY_MIN_COOLING": 0.45,
142
+ "ERV_EFFICIENCY_MAX_COOLING": 0.6,
143
+ "OAT_LOW_THRESHOLD": 32.0,
144
+ "OAT_HIGH_THRESHOLD": 80.0,
145
+ "ERV_DEGF_ERR_THRES": 2.0,
146
+ "ERV_OAT_ENTER_COL": TEST_ERV_OAT_ENTER_COL,
147
+ "ERV_OAT_LEAVING_COL": TEST_ERV_OAT_LEAVING_COL,
148
+ "ERV_EAT_ENTER_COL": TEST_ERV_EAT_ENTER_COL,
149
+ "ERV_EAT_LEAVING_COL": TEST_ERV_EAT_LEAVING_COL,
150
+ "SUPPLY_VFD_SPEED_COL": TEST_SUPPLY_VFD_SPEED_COL,
151
+ }
152
+ )
153
+ assert "should be a float between 0.0 and 1.0" in str(excinfo.value)
154
+
155
+
156
+ class TestFaultOnMissingColumns:
157
+
158
+ def test_missing_column(self):
159
+ """Test that MissingColumnError is raised if any required column is None or missing."""
160
+ with pytest.raises(MissingColumnError) as excinfo:
161
+ FaultConditionSixteen(
162
+ {
163
+ "ERV_EFFICIENCY_MIN_HEATING": 0.65,
164
+ "ERV_EFFICIENCY_MAX_HEATING": 0.8,
165
+ "ERV_EFFICIENCY_MIN_COOLING": 0.45,
166
+ "ERV_EFFICIENCY_MAX_COOLING": 0.6,
167
+ "OAT_LOW_THRESHOLD": 32.0,
168
+ "OAT_HIGH_THRESHOLD": 80.0,
169
+ "ERV_DEGF_ERR_THRES": 2.0,
170
+ "ERV_OAT_ENTER_COL": TEST_ERV_OAT_ENTER_COL,
171
+ "ERV_OAT_LEAVING_COL": None, # Missing column
172
+ "ERV_EAT_ENTER_COL": TEST_ERV_EAT_ENTER_COL,
173
+ "ERV_EAT_LEAVING_COL": TEST_ERV_EAT_LEAVING_COL,
174
+ "SUPPLY_VFD_SPEED_COL": TEST_SUPPLY_VFD_SPEED_COL,
175
+ }
176
+ ).apply(
177
+ pd.DataFrame(
178
+ {
179
+ TEST_ERV_OAT_ENTER_COL: [10, 10, 10],
180
+ TEST_ERV_EAT_ENTER_COL: [70, 70, 70],
181
+ TEST_ERV_EAT_LEAVING_COL: [60, 60, 60],
182
+ TEST_SUPPLY_VFD_SPEED_COL: [0.5, 0.5, 0.5],
183
+ }
184
+ )
185
+ )
186
+ assert "One or more required columns are missing or None" in str(excinfo.value)
187
+
188
+
189
+ if __name__ == "__main__":
190
+ pytest.main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: open_fdd
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: A package for fault detection and diagnosis in HVAC systems
5
5
  Home-page: https://github.com/bbartling/open-fdd
6
6
  Author: Ben Bartling
@@ -39,20 +39,29 @@ pip install open-fdd
39
39
  For running Jupyter notebooks, I recommend using Visual Studio Code with the Jupyter notebook extension installed, which offers a seamless experience directly within the editor. Be sure to explore the `examples` directory for Jupyter notebook tutorials. If you have your own FDD experiences to share, feel free to contribute by creating a notebook (`.ipynb`). You’re welcome to reach out to me directly, and I can push your example to GitHub on your behalf, which might be a simpler process than submitting a pull request (PR), especially if you're just sharing an example rather than developing `open-fdd`.
40
40
 
41
41
  ## Project goals
42
- These are some basic project goals to make this into an interactive FDD application.
43
- - [x] finish `air_handling_unit` faults and reports based on ASHRAE and NIST
44
- - [x] publish to PyPI as Python library
45
- - [ ] make a few IPython notebook tutorials AHU FDD examples with `BRICK` meta data integration.
46
- - [ ] make a guide for fault `parameters` like error thresholds, etc.
47
- - [ ] make `central_plant` faults, IPython reports, and examples.
48
- - [ ] make `energy_efficiency` faults, IPython reports, and examples to `optimize` in reducing energy consumption.
49
- - [ ] make `metering`, faults, IPython reports, and examples to possibly model utility metering data.
50
- - [ ] create SQL example to read data from time series db and write back to SQL to then read faults in Grafana.
51
- - [ ] other? Certainly! As ChatGPT would eagerly say!
42
+ The following are key objectives to enhance this project into a fully interactive Fault Detection and Diagnostics (FDD) application.
52
43
 
44
+ ### Completed
45
+ - [x] Develop and finalize `air_handling_unit` fault conditions and reports, aligning with ASHRAE and NIST standards.
46
+ - [x] Publish the project as a Python library on PyPI.
53
47
 
54
- ## Contribute
48
+ ### In Progress
49
+ - [ ] Create IPython notebook tutorials showcasing AHU FDD examples, incorporating BRICK metadata integration.
50
+ - [ ] Extend the project to include `central_plant` fault conditions, IPython reports, and example applications for boiler and chiller systems.
51
+
52
+
53
+ ### Upcoming
54
+ - [ ] Design `energy_efficiency` fault detection modules, including IPython reports and examples focused on optimizing energy consumption.
55
+ - [ ] Develop `metering` fault conditions, along with IPython reports and examples, potentially modeling utility metering data.
56
+ - [ ] Implement SQL integration examples for reading data from a time series database, writing back to SQL, and visualizing faults in Grafana.
55
57
 
58
+ ### Future Considerations
59
+ Explore additional features and enhancements as the project evolves.
60
+ - [ ] Explore additional features and enhancements as the project evolves.
61
+ - [ ] Develop a comprehensive guide on a github.io website (or other?) for defining fault parameters, including error thresholds and other critical settings.
62
+
63
+
64
+ ## Contribute
56
65
  If you have suggestions for improving developer best practices or solutions, please feel free to reach out to me directly using my contact information or Git issue/discussion. I primarily work on Windows with multiple versions of Python installed, with Python 3.12.x as my default version. You can download the latest version of Python here:
57
66
  * https://www.python.org/downloads/
58
67
 
@@ -0,0 +1,31 @@
1
+ open_fdd/__init__.py,sha256=iGj8QTOZJUTE4nNnBiCHXEXsOdV6YvKcGiLrnOusJCg,1411
2
+ open_fdd/air_handling_unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ open_fdd/air_handling_unit/faults/__init__.py,sha256=NBdGNlp0MTUPNB-43zgnYs3iYqFhEeNa3q_VgDPGAoo,91603
4
+ open_fdd/air_handling_unit/faults/fault_condition.py,sha256=UN2_k2AZWMDoO4oPAnJW3fvhkHlMkLXZikzU2lXAOuQ,2364
5
+ open_fdd/air_handling_unit/faults/helper_utils.py,sha256=-Bd1mMMLnFmpNPe7eC23kMJxPtazsIyz5P7W6Yqlu4w,12580
6
+ open_fdd/air_handling_unit/faults/shared_utils.py,sha256=Kp8ZUBhtrh-jU2Q_bbXTpnbVVUAyacp41tDMknY50i4,2252
7
+ open_fdd/air_handling_unit/reports/__init__.py,sha256=iXIqEaaO_8yRnlVUuYMcc_L0xQf3iqSYi3ykIzeGBf8,40124
8
+ open_fdd/air_handling_unit/reports/fault_report.py,sha256=QxYLJzoLTwf1N0nls2XMmhHJvBSgGCBNT0KxA59QG4Y,1442
9
+ open_fdd/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ open_fdd/tests/ahu/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ open_fdd/tests/ahu/test_ahu_fc1.py,sha256=ojpdYGZtuIYAKnZ4W9KhxQuoyXnGEI5N7braQXh3kAw,5437
12
+ open_fdd/tests/ahu/test_ahu_fc10.py,sha256=niYL7fi6OlgP0wnF8hNh9A07PLzHiRZkyRkrA1zoL2s,4577
13
+ open_fdd/tests/ahu/test_ahu_fc11.py,sha256=mdXlGiEMPkPfshf3NN_nJavL74e4HCmkJQMu86aZc6Q,4723
14
+ open_fdd/tests/ahu/test_ahu_fc12.py,sha256=5T-XcM6xm9KHrc121uPGC9JWLCYehrAYk0KcbmGgYjw,5848
15
+ open_fdd/tests/ahu/test_ahu_fc13.py,sha256=vJlSy4e2WV9hx02P0SiJ75I1DWL2lZ0p7-AWlw97pks,5725
16
+ open_fdd/tests/ahu/test_ahu_fc14.py,sha256=MU0LKqIuoQ_dJ0Kij8_A0YyimCMvUwL6IlMwpQhDbqI,8052
17
+ open_fdd/tests/ahu/test_ahu_fc15.py,sha256=SIolJ9vnJwnpKfRW2ALugYWySuIiZ9_repWP9fdb5H4,7661
18
+ open_fdd/tests/ahu/test_ahu_fc16.py,sha256=3xhNfN2pKon-2_jyCUSh_JEKSv9jYGiTxRjLOL7uvVI,8052
19
+ open_fdd/tests/ahu/test_ahu_fc2.py,sha256=CjmO_WUyaSHs17ifCCew3GBJ43nYG55uGL0vHDZpAq8,4736
20
+ open_fdd/tests/ahu/test_ahu_fc3.py,sha256=NB6pOXDS-R4P0LNoRN8ItAqhhLnGnGuAHZha32Qw-hE,4658
21
+ open_fdd/tests/ahu/test_ahu_fc4.py,sha256=vV8jEnFuNGLfhCoTVz29RsIcoDpDOMWg722G0aBEXaE,6304
22
+ open_fdd/tests/ahu/test_ahu_fc5.py,sha256=TpSQTBIF591Q3mVaBeJ6HyqPWhVHmD_gSZNEIFT6yyg,6538
23
+ open_fdd/tests/ahu/test_ahu_fc6.py,sha256=66dwv0EBU_ujZK-J9Ki5a3fnXlk17nOwmtKDiQOHdbM,10351
24
+ open_fdd/tests/ahu/test_ahu_fc7.py,sha256=sABbw2m7WlAXbsqfDD323vfEfg606ThI0QzQyB-OjFo,2469
25
+ open_fdd/tests/ahu/test_ahu_fc8.py,sha256=UZy6BP2PgV1FROUPqMORTx8YnT5ZvqVDhut_Ar81494,4663
26
+ open_fdd/tests/ahu/test_ahu_fc9.py,sha256=b-eIzhNzjZUjVNsP0JAHkOgZu-BtDuPeNnblVVm-jU8,4796
27
+ open_fdd-0.1.6.dist-info/LICENSE,sha256=eghao_GGx_0gB2Sll3x2vV29knONEzUQKrkaXpX1F7w,1087
28
+ open_fdd-0.1.6.dist-info/METADATA,sha256=IER_eG7nwqbDIoDA2a9LyFgh20pOeBYhAGHlhT1PFLo,6958
29
+ open_fdd-0.1.6.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
30
+ open_fdd-0.1.6.dist-info/top_level.txt,sha256=Q7sB6UB2d8Ch1v_xIsTiNegmgcCXPkwkrxK3ug6VEOs,9
31
+ open_fdd-0.1.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (74.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,127 +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 FaultConditionEight(FaultCondition):
11
- """Class provides the definitions for Fault Condition 8.
12
- Supply air temperature and mix air temperature should
13
- be approx equal in economizer mode.
14
- """
15
-
16
- def __init__(self, dict_):
17
- super().__init__()
18
- self.delta_t_supply_fan = float
19
- self.mix_degf_err_thres = float
20
- self.supply_degf_err_thres = float
21
- self.ahu_min_oa_dpr = float
22
- self.mat_col = str
23
- self.sat_col = str
24
- self.economizer_sig_col = str
25
- self.cooling_sig_col = str
26
- self.troubleshoot_mode = bool # default should be False
27
- self.rolling_window_size = int
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
-
43
- self.set_attributes(dict_)
44
-
45
- # Set required columns specific to this fault condition
46
- self.required_columns = [
47
- self.mat_col,
48
- self.sat_col,
49
- self.economizer_sig_col,
50
- self.cooling_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
-
93
- self.check_analog_pct(df, columns_to_check)
94
-
95
- df["sat_fan_mat"] = abs(
96
- df[self.sat_col] - self.delta_t_supply_fan - df[self.mat_col]
97
- )
98
- df["sat_mat_sqrted"] = np.sqrt(
99
- self.supply_degf_err_thres**2 + self.mix_degf_err_thres**2
100
- )
101
-
102
- df["combined_check"] = (
103
- (df["sat_fan_mat"] > df["sat_mat_sqrted"])
104
- & (df[self.economizer_sig_col] > self.ahu_min_oa_dpr)
105
- & (df[self.cooling_sig_col] < 0.1)
106
- )
107
-
108
- # Rolling sum to count consecutive trues
109
- rolling_sum = (
110
- df["combined_check"].rolling(window=self.rolling_window_size).sum()
111
- )
112
- # Set flag to 1 if rolling sum equals the window size
113
- df["fc8_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
114
-
115
- if self.troubleshoot_mode:
116
- print("Troubleshoot mode enabled - not removing helper columns")
117
- sys.stdout.flush()
118
- del df["sat_fan_mat"]
119
- del df["sat_mat_sqrted"]
120
- del df["combined_check"]
121
-
122
- return df
123
-
124
- except MissingColumnError as e:
125
- print(f"Error: {e.message}")
126
- sys.stdout.flush()
127
- raise e
@@ -1,126 +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 FaultConditionEleven(FaultCondition):
10
- """Class provides the definitions for Fault Condition 11.
11
- Outside air temperature too low for 100% outdoor
12
- air cooling in economizer cooling mode.
13
- Economizer performance fault
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.sat_setpoint_col = str
22
- self.oat_col = str
23
- self.cooling_sig_col = str
24
- self.economizer_sig_col = str
25
- self.troubleshoot_mode = bool # default False
26
- self.rolling_window_size = int
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
-
42
- self.set_attributes(dict_)
43
-
44
- # Set required columns specific to this fault condition
45
- self.required_columns = [
46
- self.sat_setpoint_col,
47
- self.oat_col,
48
- self.cooling_sig_col,
49
- self.economizer_sig_col,
50
- ]
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
-
69
- def get_required_columns(self) -> str:
70
- """Returns a string representation of the required columns."""
71
- return (
72
- f"{self.equation_string}"
73
- f"{self.description_string}"
74
- f"{self.required_column_description}"
75
- f"{self.mapped_columns}"
76
- )
77
-
78
- def apply(self, df: pd.DataFrame) -> pd.DataFrame:
79
- try:
80
- # Ensure all required columns are present
81
- self.check_required_columns(df)
82
-
83
- if self.troubleshoot_mode:
84
- self.troubleshoot_cols(df)
85
-
86
- # Check analog outputs [data with units of %] are floats only
87
- columns_to_check = [
88
- self.economizer_sig_col,
89
- self.cooling_sig_col,
90
- ]
91
- self.check_analog_pct(df, columns_to_check)
92
-
93
- df["oat_plus_oaterror"] = df[self.oat_col] + self.outdoor_degf_err_thres
94
- df["satsp_delta_saterr"] = (
95
- df[self.sat_setpoint_col]
96
- - self.delta_t_supply_fan
97
- - self.supply_degf_err_thres
98
- )
99
-
100
- df["combined_check"] = (
101
- (df["oat_plus_oaterror"] < df["satsp_delta_saterr"])
102
- # verify ahu is running in OS 3 clg mode in 100 OA
103
- & (df[self.cooling_sig_col] > 0.01)
104
- & (df[self.economizer_sig_col] > 0.9)
105
- )
106
-
107
- # Rolling sum to count consecutive trues
108
- rolling_sum = (
109
- df["combined_check"].rolling(window=self.rolling_window_size).sum()
110
- )
111
- # Set flag to 1 if rolling sum equals the window size
112
- df["fc11_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
113
-
114
- if self.troubleshoot_mode:
115
- print("Troubleshoot mode enabled - not removing helper columns")
116
- sys.stdout.flush()
117
- del df["oat_plus_oaterror"]
118
- del df["satsp_delta_saterr"]
119
- del df["combined_check"]
120
-
121
- return df
122
-
123
- except MissingColumnError as e:
124
- print(f"Error: {e.message}")
125
- sys.stdout.flush()
126
- raise e