ecopipeline 0.8.3__py3-none-any.whl → 0.8.4__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.
@@ -3,7 +3,7 @@ import numpy as np
3
3
  import datetime as dt
4
4
  from ecopipeline import ConfigManager
5
5
 
6
- def flag_boundary_alarms(df: pd.DataFrame, config : ConfigManager, default_fault_time : int = 15, site: str = "") -> pd.DataFrame:
6
+ def flag_boundary_alarms(df: pd.DataFrame, config : ConfigManager, default_fault_time : int = 15, site: str = "", full_days : list = None) -> pd.DataFrame:
7
7
  """
8
8
  Function will take a pandas dataframe and location of alarm information in a csv,
9
9
  and create an dataframe with applicable alarm events
@@ -24,6 +24,8 @@ def flag_boundary_alarms(df: pd.DataFrame, config : ConfigManager, default_fault
24
24
  the fault_time column in Varriable_Names.csv
25
25
  site: str
26
26
  string of site name if processing a particular site in a Variable_Names.csv file with multiple sites. Leave as an empty string if not aplicable.
27
+ full_days : list
28
+ list of pd.Datetimes that should be considered full days here. If set to none, will take any day at all present in df
27
29
 
28
30
  Returns
29
31
  -------
@@ -52,7 +54,8 @@ def flag_boundary_alarms(df: pd.DataFrame, config : ConfigManager, default_fault
52
54
  bounds_df['fault_time'] = default_fault_time
53
55
 
54
56
  idx = df.index
55
- unique_days = pd.to_datetime(pd.Series(idx).dt.normalize().unique())
57
+ if full_days is None:
58
+ full_days = pd.to_datetime(pd.Series(idx).dt.normalize().unique())
56
59
 
57
60
  bounds_df = bounds_df.loc[:, ["variable_name", "high_alarm", "low_alarm", "fault_time", "pretty_name"]]
58
61
  bounds_df.dropna(axis=0, thresh=2, inplace=True)
@@ -69,30 +72,11 @@ def flag_boundary_alarms(df: pd.DataFrame, config : ConfigManager, default_fault
69
72
  upper_mask = df[bound_var] > bounds["high_alarm"]
70
73
  if pd.isna(bounds['fault_time']):
71
74
  bounds['fault_time'] = default_fault_time
72
- for day in unique_days:
73
- next_day = day + pd.Timedelta(days=1)
74
- # low alert
75
- low_filtered_df = lower_mask.loc[(lower_mask.index >= day) & (lower_mask.index < next_day)]
76
- low_consecutive_condition = low_filtered_df.rolling(window=bounds["fault_time"]).min() == 1
77
- if low_consecutive_condition.any():
78
- first_true_index = low_consecutive_condition.idxmax()
79
- adjusted_time = first_true_index - pd.Timedelta(minutes=bounds["fault_time"]-1)
80
- alarm_string = f"Lower bound alarm for {bounds['pretty_name']} (first one at {adjusted_time.strftime('%H:%M')})."
81
- if day in alarms:
82
- alarms[day].append([bound_var, alarm_string])
83
- else:
84
- alarms[day] = [[bound_var, alarm_string]]
85
- # high alert
86
- up_filtered_df = upper_mask.loc[(upper_mask.index >= day) & (upper_mask.index < next_day)]
87
- up_consecutive_condition = up_filtered_df.rolling(window=bounds["fault_time"]).min() == 1
88
- if up_consecutive_condition.any():
89
- first_true_index = up_consecutive_condition.idxmax()
90
- adjusted_time = first_true_index - pd.Timedelta(minutes=bounds["fault_time"]-1)
91
- alarm_string = f"Upper bound alarm for {bounds['pretty_name']} (first one at {adjusted_time.strftime('%H:%M')})."
92
- if day in alarms:
93
- alarms[day].append([bound_var, alarm_string])
94
- else:
95
- alarms[day] = [[bound_var, alarm_string]]
75
+ for day in full_days:
76
+ if bounds['fault_time'] < 1 :
77
+ print(f"Could not process alarm for {bound_var}. Fault time must be greater than or equal to 1 minute.")
78
+ _check_and_add_alarm(df, lower_mask, alarms, day, bounds["fault_time"], bound_var, bounds['pretty_name'], 'Lower')
79
+ _check_and_add_alarm(df, upper_mask, alarms, day, bounds["fault_time"], bound_var, bounds['pretty_name'], 'Upper')
96
80
  events = {
97
81
  'start_time_pt' : [],
98
82
  'end_time_pt' : [],
@@ -112,6 +96,34 @@ def flag_boundary_alarms(df: pd.DataFrame, config : ConfigManager, default_fault
112
96
  event_df.set_index('start_time_pt', inplace=True)
113
97
  return event_df
114
98
 
99
+ def _check_and_add_alarm(df : pd.DataFrame, mask : pd.Series, alarms_dict, day, fault_time : int, var_name : str, pretty_name : str, alarm_type : str = 'Lower'):
100
+ # KNOWN BUG : Avg value during fault time excludes the first (fault_time-1) minutes of each fault window
101
+ next_day = day + pd.Timedelta(days=1)
102
+ filtered_df = mask.loc[(mask.index >= day) & (mask.index < next_day)]
103
+ consecutive_condition = filtered_df.rolling(window=fault_time).min() == 1
104
+ if consecutive_condition.any():
105
+ group = (consecutive_condition != consecutive_condition.shift()).cumsum()
106
+ streaks = consecutive_condition.groupby(group).agg(['sum', 'size', 'idxmin'])
107
+ true_streaks = streaks[consecutive_condition.groupby(group).first()]
108
+ longest_streak_length = true_streaks['size'].max()
109
+ avg_streak_length = true_streaks['size'].mean() + fault_time-1
110
+ longest_group = true_streaks['size'].idxmax()
111
+ streak_indices = consecutive_condition[group == longest_group].index
112
+ starting_index = streak_indices[0]
113
+
114
+ day_df = df.loc[(df.index >= day) & (df.index < next_day)]
115
+ average_value = day_df.loc[consecutive_condition, var_name].mean()
116
+
117
+ # first_true_index = consecutive_condition.idxmax()
118
+ # because first (fault_time-1) minutes don't count in window
119
+ adjusted_time = starting_index - pd.Timedelta(minutes=fault_time-1)
120
+ adjusted_longest_streak_length = longest_streak_length + fault_time-1
121
+ alarm_string = f"{alarm_type} bound alarm for {pretty_name} (longest at {adjusted_time.strftime('%H:%M')} for {adjusted_longest_streak_length} minutes). Avg fault time : {avg_streak_length} minutes, Avg value during fault: {average_value}"
122
+ if day in alarms_dict:
123
+ alarms_dict[day].append([var_name, alarm_string])
124
+ else:
125
+ alarms_dict[day] = [[var_name, alarm_string]]
126
+
115
127
  # def flag_dhw_outage(df: pd.DataFrame, daily_df : pd.DataFrame, dhw_outlet_column : str, supply_temp : int = 110, consecutive_minutes : int = 15) -> pd.DataFrame:
116
128
  # """
117
129
  # Parameters
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ecopipeline
3
- Version: 0.8.3
3
+ Version: 0.8.4
4
4
  Summary: Contains functions for use in Ecotope Datapipelines
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: License :: OSI Approved :: GNU General Public License (GPL)
@@ -1,6 +1,6 @@
1
1
  ecopipeline/__init__.py,sha256=d48mO5La6OrQDkRe_qqoY6lUx7x-e8krOH388jmWjwU,218
2
2
  ecopipeline/event_tracking/__init__.py,sha256=q49j46fXMUjNUPzL4FvXEppB93i3lUni-QUZpp61tt0,64
3
- ecopipeline/event_tracking/event_tracking.py,sha256=PHy4xYv71u79UZqFuXnMU7KRwbzOCIc-NNqArcmG9FM,12311
3
+ ecopipeline/event_tracking/event_tracking.py,sha256=W7_rU_ZbeyMnHD6pV3k27bTvS4EA8MXOFtBtZ9uRc6E,13184
4
4
  ecopipeline/extract/__init__.py,sha256=gQ3sak6NJ63Gpo-hZXrtZfeKOTHLRyAVXfTgxxRpqPo,675
5
5
  ecopipeline/extract/extract.py,sha256=Fch2IvqGxMClKGniiJiKqyJhcFDwkckaeiGQRVnUGUg,46708
6
6
  ecopipeline/load/__init__.py,sha256=NLa_efQJZ8aP-J0Y5xx9DP7mtfRH9jY6Jz1ZMZN_BAA,292
@@ -12,8 +12,8 @@ ecopipeline/transform/transform.py,sha256=DBQD4WqKmdXnGQMAj6tg75HtXiSemIc7c6nZxz
12
12
  ecopipeline/utils/ConfigManager.py,sha256=-g1wtExdvhYO5Y6Q3cRbywa__DxRMFruLrB4YanwaPY,12168
13
13
  ecopipeline/utils/__init__.py,sha256=ccWUR0m7gD9DfcgsxBCLOfi4lho6RdYuB2Ugy_g6ZdQ,28
14
14
  ecopipeline/utils/unit_convert.py,sha256=VFh1we2Y8KV3u21BeWb-U3TlZJXo83q5vdxxkpgcuME,3064
15
- ecopipeline-0.8.3.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- ecopipeline-0.8.3.dist-info/METADATA,sha256=N0ZTWUbmVtj99GIrkWfZ8gSdwHiQSla0TOJ9nMDiBCU,2329
17
- ecopipeline-0.8.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
18
- ecopipeline-0.8.3.dist-info/top_level.txt,sha256=WOPFJH2LIgKqm4lk2OnFF5cgVkYibkaBxIxgvLgO7y0,12
19
- ecopipeline-0.8.3.dist-info/RECORD,,
15
+ ecopipeline-0.8.4.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ ecopipeline-0.8.4.dist-info/METADATA,sha256=L3soJWG2f8FxVbFy6UWRRNdM6md-AqxlrvUyHEdItT8,2329
17
+ ecopipeline-0.8.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
18
+ ecopipeline-0.8.4.dist-info/top_level.txt,sha256=WOPFJH2LIgKqm4lk2OnFF5cgVkYibkaBxIxgvLgO7y0,12
19
+ ecopipeline-0.8.4.dist-info/RECORD,,