Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect passing valves #14

Open
wants to merge 84 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
c9cc034
initial commit for app that detects passing valves
carlosduarteroa Oct 15, 2020
d995d87
developed query to return valve command points
carlosduarteroa Oct 15, 2020
f3fd53d
develop query that gets points needed for detect passing valves
carlosduarteroa Oct 16, 2020
fb24440
narrow scope of app to vav reheat valves
carlosduarteroa Oct 16, 2020
3ed1c5d
developed clean and analysis sections for the app
carlosduarteroa Oct 21, 2020
77469a3
added func to check existance of container folders
carlosduarteroa Oct 22, 2020
c378a2b
adjusted the color of the plots
carlosduarteroa Oct 22, 2020
673e833
fixed bug in bad valve decision
carlosduarteroa Oct 22, 2020
e9e0e13
improved the formating of the plot
carlosduarteroa Oct 27, 2020
6abc00f
changed variable names
carlosduarteroa Oct 29, 2020
ffcd9fe
added functionality to download AHU valve data
carlosduarteroa Oct 29, 2020
9a57ced
added functionality to download AHU valve data
carlosduarteroa Oct 29, 2020
e41a71c
deleted debug snippet
carlosduarteroa Oct 29, 2020
8431778
delete merge conflict messages
carlosduarteroa Oct 29, 2020
a161a69
cleaned up comments and variable names
carlosduarteroa Oct 30, 2020
27d33a3
example of outputs
carlosduarteroa Oct 30, 2020
c74ea63
deleted debug code snippet
carlosduarteroa Oct 30, 2020
3bef825
refactored quiery and qualify steps into a function
carlosduarteroa Dec 1, 2020
e00dbef
refactored fetch step into a function
carlosduarteroa Dec 1, 2020
284115a
added descriptions to clean functions
carlosduarteroa Dec 1, 2020
d8d53d7
refactored and added comments for the helper tool functions
carlosduarteroa Dec 1, 2020
4f7a94c
refactored the analyze steps
carlosduarteroa Dec 1, 2020
d4c781c
fixed incorrect dictionary definition
carlosduarteroa Dec 1, 2020
fc70f33
fixed missing parameter in function
carlosduarteroa Dec 2, 2020
44396eb
Rewrote the app description.
carlosduarteroa Dec 2, 2020
d5c2b34
added function to subset data by building occupancy
carlosduarteroa Dec 4, 2020
8986ea5
added check on vav supply air temperature
carlosduarteroa Dec 5, 2020
d90e454
added function to delete transient data points
carlosduarteroa Dec 22, 2020
99a08af
do a more detailed analysis on bldg data with airflow vals
carlosduarteroa Dec 23, 2020
1420d24
added functionality to return inflection point of sigmoid curve
carlosduarteroa Dec 30, 2020
57d9295
added functionality to use air flow data to detect passing valves
carlosduarteroa Dec 31, 2020
121cf42
changed assessment to detect pass vlv by using valve open data
carlosduarteroa Dec 31, 2020
4dca0ae
added function to check duplicate plot files
carlosduarteroa Jan 4, 2021
69a888f
added conditions for when airflow density is unimodal
carlosduarteroa Jan 4, 2021
eb2d451
changed the conditions for detecting passing valve
carlosduarteroa Jan 4, 2021
038c3d0
fixed bugs when df is none and missing arg
carlosduarteroa Jan 4, 2021
e4693ec
added function to clean up final report of passing valves
carlosduarteroa Jan 6, 2021
8f691fe
added function to make timeseries plots of valve data that was detect…
carlosduarteroa Jan 7, 2021
7f2e3d1
refactored plot function to make plots for good operation valve data
carlosduarteroa Jan 7, 2021
2a8f077
processed a different timeframe
carlosduarteroa Apr 29, 2021
381f9a1
added option for printout and conditions if faults don't exist
carlosduarteroa Nov 5, 2021
f0f3d14
added parameters to function so it can run with Brick or mortar data
carlosduarteroa Nov 5, 2021
3cc775d
modified rules for detecting long and short term passing vlvs
carlosduarteroa Nov 5, 2021
88323df
delete NAs in airflow data before calculating density line
carlosduarteroa Nov 5, 2021
1da2441
added message for when there is no airflow data
carlosduarteroa Nov 5, 2021
fbaa0e2
added legends to timeseries plots
carlosduarteroa Nov 5, 2021
2853a8c
adjusted position of 'bad statistic' text within plot
carlosduarteroa Nov 5, 2021
38f5eb6
modified method to remove missing stream timestamps
carlosduarteroa Nov 11, 2021
63daa95
added legends to plots
carlosduarteroa Nov 11, 2021
13a4748
added helper script to prepare external non-mortar data for analysis
carlosduarteroa Nov 11, 2021
7bba321
working script for gt bldgs
carlosduarteroa Nov 22, 2021
360d79d
added new data file
carlosduarteroa Nov 30, 2021
7efdcde
added parameter to estimate accuarcy of airflow measurement
carlosduarteroa Dec 9, 2021
ef27b9d
updated to latest brick syntax
carlosduarteroa Feb 11, 2022
48cf875
refactored code to avoid duplicates
carlosduarteroa Feb 11, 2022
fed94f9
added logger outputs
carlosduarteroa Feb 15, 2022
0e73996
fixed plotting bugs
carlosduarteroa Feb 15, 2022
e273d07
verify that sensors are reporting variation in measurements
carlosduarteroa Feb 15, 2022
b273e45
modification to plots
carlosduarteroa Feb 16, 2022
8b4e2fb
modification to output of report
carlosduarteroa Feb 16, 2022
aa8b719
added analysis to datasets
carlosduarteroa Feb 16, 2022
13097c5
added variables in the find bad vlv operation function
carlosduarteroa Feb 18, 2022
33c5c2d
additional analysis
carlosduarteroa Feb 18, 2022
e6a5298
changed vlv model to unscaled sigmoid
carlosduarteroa Feb 22, 2022
92d9861
check if columns are available
carlosduarteroa Feb 22, 2022
c13adde
improved the way it detected fault operation
carlosduarteroa Feb 23, 2022
adec47b
updated/added analysis to gt ext building
carlosduarteroa Feb 24, 2022
81ee6e6
drop na columns for required streams
carlosduarteroa Feb 24, 2022
d175878
use vlv model to categoize valve operation
carlosduarteroa Feb 24, 2022
bb50746
visualize short term fault in ts graphs
carlosduarteroa Mar 2, 2022
9f0bc09
change exceed threshold from 5 to 10 degF
carlosduarteroa Mar 2, 2022
7c1942e
heat loss calc and fault manage improvments
carlosduarteroa Mar 2, 2022
4d23065
add air flow cutoff in plots
carlosduarteroa Mar 4, 2022
43f8d30
final parameters for paper
carlosduarteroa Mar 4, 2022
3c6afbe
updated parameters for paper
carlosduarteroa Mar 9, 2022
4b99e5f
fixed bug for processing fault dates
carlosduarteroa Mar 9, 2022
a6483a0
various improvements to detection algorithm
carlosduarteroa Mar 9, 2022
000a5a7
script to analyze results in aggregate
carlosduarteroa Mar 10, 2022
16e1006
output vlv_df and fixed consecutive timestamp bug
carlosduarteroa Mar 14, 2022
f594326
udpated analysis script
carlosduarteroa Mar 16, 2022
c3f1f8b
lowered threshold to avoid more false positive in sensor faults
carlosduarteroa Mar 16, 2022
aa826cf
modify plot size and increase font size
carlosduarteroa Jun 14, 2022
caab670
2nd draft review changes
carlosduarteroa Jun 14, 2022
f307c2c
improved plot quality to 600dpi
carlosduarteroa Aug 30, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions detect_passing_valves/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Detect passing valves in HVAC equipment

This app detects valves in HVAC equipment that do not close fully even when actuated to a fully closed position, also known as “passing valves”. The application compares fluid temperatures upstream and downstream from the valve and calculates the expected long-term difference between the two fluid streams when the valve is currently closed, and has been closed for some time. The app then analyzes the expected trends with the actual data to determine if the valve is in good operating condition or malfunctioning.

This app produces a plot for each analyzed valve with file name formatted as `<site name>-<equipment name>-<valve name>.png` when run. Each plot shows a solid green horizontal line that represents the average temperature difference between the downstream and upstream fluids when valve is commanded closed, a dashed purple line shows the expected correct operating behavior trend of the valve (based on the green points), a solid pink horizontal line shows the average temperature difference when the application detected a possible passing valve (based on the red points). The ‘Bad ratio’ value is a ratio of the number of bad operating point values to goodoperating point values. Each file is either allocated in a 'good' or 'bad' folder depending if the analyzed valve is operating correctly (good folder) or malfunctioning (bad folder).
141 changes: 141 additions & 0 deletions detect_passing_valves/aggregate_results.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
from os.path import join
import os
import pandas as pd
import numpy as np

def parse_dict_list_file(line):

dictionary = dict()
pairs = line.strip().strip(",").strip('{}').split(', ')
for pr in pairs:
pair = pr.split(': ')
dictionary[pair[0].strip('\'\'\"\"')] = pair[1].strip('\'\'\"\"')

return dictionary

def separate_heat_transfer_col(df, col):
heat_tfr_pwer = []
heat_tfr_enrg = []
for hl in df[col]:
if pd.notnull(hl):
hl = hl.strip('()').split(", ")
heat_tfr_pwer.append(float(hl[0]))
heat_tfr_enrg.append(float(hl[1]))
else:
heat_tfr_pwer.append(np.nan)
heat_tfr_enrg.append(np.nan)

return heat_tfr_pwer, heat_tfr_enrg

if __name__ == '__main__':
dat_folder = join('with_airflow_checks_year_start', 'csv_data')
project_folder = join('./', 'external_analysis')

mortar_dat_file = join(project_folder, 'MORTAR', 'lg_4hr_shrt_1hr_test_no_aflw_req_10C_threshold')
bear_dat_file = join(project_folder, 'bldg_trc_rs', 'lg_4hr_shrt_1hr_test_no_aflw_req_10C_threshold')
lion_dat_file = join(project_folder, 'bldg_gt_pr', 'lg_4hr_shrt_1hr_test_no_aflw_req_10C_threshold')

all_datasets = []
for dataset in [mortar_dat_file, bear_dat_file, lion_dat_file]:
# Perform additional analysis
f = open(join(dataset, 'minimum_airflow_values.txt'), 'r')
lines = f.readlines()
f.close()

vav_results = []
for line in lines:
vav_results.append(parse_dict_list_file(line))

vav_results = pd.DataFrame.from_records(vav_results)
all_datasets.append(vav_results)

all_datasets = pd.concat(all_datasets).reset_index(drop=True)

# clean dataframe
numeric_cols = ['minimum_air_flow_cutoff', 'long_t', 'long_tbad', 'bad_ratio', 'long_to']
avail_cols = list(set(all_datasets.columns).intersection(set(numeric_cols)))
all_datasets[avail_cols] = all_datasets[avail_cols].apply(pd.to_numeric, errors='coerce')

all_datasets = all_datasets.dropna(subset=['folder'])

all_datasets['folder_short'] = all_datasets['folder'].apply(os.path.basename)


# add rest of info including heat loss due to passing valves
all_passing_valve_results = []
for dataset in [mortar_dat_file, bear_dat_file, lion_dat_file]:
final_df = pd.read_csv(join(dataset, 'passing_valve_results.csv'), index_col=0)
all_passing_valve_results.append(final_df)

all_passing_valve_results = pd.concat(all_passing_valve_results).reset_index(drop=True)

all_datasets = pd.merge(all_datasets, all_passing_valve_results, how='left', on=['vlv', 'site', 'equip'])

# separate heat rate loss from energy loss
heat_loss_pwer, heat_loss_enrg = separate_heat_transfer_col(df=all_datasets, col='heat_loss_pwr-avg_nrgy-sum')

all_datasets['heat_loss_pwr'] = heat_loss_pwer
all_datasets['heat_loss_enrg'] = heat_loss_enrg

# separate intentional heat rate
heat_intend_pwer, heat_intend_enrg = separate_heat_transfer_col(df=all_datasets, col='heat_intentional_pwr-avg_nrgy-sum')

all_datasets['heat_intend_pwr'] = heat_intend_pwer
all_datasets['heat_intend_enrg'] = heat_intend_enrg


# summary statistics on long term difference for each site
site_grp = all_datasets.groupby(['site'])
folder_grp = all_datasets.groupby(['folder_short'])
vav_results_grp = all_datasets.groupby(['site', 'folder_short'])
grp_dat_stats = vav_results_grp['long_t'].describe()
folder_grp['long_t'].describe()

# summary statistics on long term difference for all data
agg_dat_grp = all_datasets.groupby(['folder_short'])
agg_dat_stats = agg_dat_grp['long_t'].describe()


# summary statistics on heat loss due to passing valves
no_sensor_faults = all_datasets.loc[all_datasets["folder_short"] != "sensor_fault"]
folder_grp_nsf = no_sensor_faults.groupby(['folder_short'])
heat_loss = folder_grp_nsf["heat_loss_enrg"].sum().sum()
heat_intent = folder_grp_nsf["heat_intend_enrg"].sum().sum()

heat_loss_ratio = heat_loss/heat_intent

# on aggregate
no_sensor_faults["long_term_fail_num_times_detected"].describe()
no_sensor_faults["long_term_fail_avg_minutes"].describe()

no_sensor_faults["short_term_fail_num_times_detected"].describe()
no_sensor_faults["short_term_fail_avg_minutes"].describe()

no_sensor_faults["heat_loss_pwr"].describe()
no_sensor_faults["heat_loss_enrg"].sum()/1000

# by site
from_btuhr_to_watts = 0.293071
site_grp_nsf = no_sensor_faults.groupby(['site'])

site_heat_loss = site_grp_nsf["heat_loss_enrg"].sum()
site_heat_intend = site_grp_nsf["heat_intend_enrg"].sum()

site_heat_loss/site_heat_intend

# by fault category
site_grp_nsf["heat_loss_pwr"].describe()*from_btuhr_to_watts

# all
all_datasets.loc[all_datasets["folder_short"] == "bad_valves", "heat_loss_enrg"]
all_datasets.loc[:,"heat_intend_enrg"]

all_datasets["heat_loss_pwr"].describe()*from_btuhr_to_watts

subset_lion = np.logical_and(all_datasets["site"] == "lion", all_datasets["folder_short"] == "bad_valves")
df_bad_lion = all_datasets.loc[subset_lion]

df_bad_lion["loss_pct"] = df_bad_lion["heat_loss_enrg"]/df_bad_lion["heat_intend_enrg"]
df_bad_lion.sort_values("loss_pct", ascending=False)


Loading