alirezaaminzadeh commited on
Commit
97a4932
·
verified ·
1 Parent(s): cfd5bc1

Add mass-balance config + LSTM-AE (ONNX/pt) + NPW localization eval_results.json

Browse files
README.md ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ library_name: pytorch
4
+ pipeline_tag: time-series-forecasting
5
+ tags:
6
+ - oil-gas
7
+ - petrochemical
8
+ - pipeline-monitoring
9
+ - leak-detection
10
+ - scada
11
+ - anomaly-detection
12
+ - lstm-autoencoder
13
+ - mass-balance
14
+ - aria-ai
15
+ model-index:
16
+ - name: pipelinewatch-leak-detector
17
+ results:
18
+ - task:
19
+ type: anomaly-detection
20
+ dataset:
21
+ name: PipelineWatch synthetic SCADA test episodes (54 held-out)
22
+ type: alirezaaminzadeh/pipelinewatch-scada-synthetic
23
+ metrics:
24
+ - type: detection_rate_overall
25
+ value: 1.0
26
+ - type: mean_time_to_detect_seconds_mass_balance
27
+ value: 70.0
28
+ - type: mean_time_to_detect_seconds_lstm_ae
29
+ value: 41.25
30
+ - type: mean_false_alarms_per_hour_mass_balance
31
+ value: 0.356
32
+ - type: mean_false_alarms_per_hour_lstm_ae
33
+ value: 3.842
34
+ ---
35
+
36
+ # PipelineWatch — Leak Detector (Mass-Balance + LSTM-Autoencoder + NPW Localization)
37
+
38
+ Two complementary leak detectors plus a best-effort negative-pressure-wave (NPW) leak-location
39
+ estimator, trained/calibrated on the fully synthetic [`pipelinewatch-scada-synthetic`](https://huggingface.co/datasets/alirezaaminzadeh/pipelinewatch-scada-synthetic)
40
+ dataset. Part of the [Aria AI](https://aria-ai.ir) `Aria PetroOps` → "Pipeline Monitoring (midstream)" module validation.
41
+
42
+ ## Data honesty
43
+
44
+ Trained and evaluated **entirely on a synthetic hydraulic/SCADA simulation** (see the dataset card).
45
+ Pipeline length, wave speed, and friction constants are assumed textbook values, not calibrated to any
46
+ real pipeline. **Do not treat the numbers below as a guarantee of field performance** — they measure
47
+ whether the *methodology* works on a controlled, honestly-labeled synthetic benchmark. A real pilot needs
48
+ re-calibration against the target line's own historian data before any threshold is trusted operationally.
49
+
50
+ ## Two detectors, an explicit trade-off — not a single "best" model
51
+
52
+ | Detector | Overall detection rate | Mean TTD (s) | False-alarm episodes (of 30 normal test) | Mean false alarms/hour |
53
+ |---|---:|---:|---:|---:|
54
+ | **Mass-balance (primary)** | 100% | 70.0 | 5 (16.7%) | 0.36 |
55
+ | LSTM-Autoencoder (fast secondary) | 100% | **41.25** | 21 (70.0%) | 3.84 |
56
+
57
+ **Mass-balance is recommended as the primary/first-line trigger** because, at an identical 100%
58
+ detection rate on the held-out test episodes, it has a far lower false-alarm rate. **The LSTM-Autoencoder
59
+ detects leaks roughly 30-40% faster on average** (see the by-severity breakdown below) and is recommended
60
+ as a fast *corroborating* secondary signal — e.g. "raise confidence" rather than "raise the alarm alone" —
61
+ given its higher false-alarm rate on this synthetic data. This is a genuine, measured trade-off, not a
62
+ modeling error; both directions are reported below rather than only publishing whichever number looks best.
63
+
64
+ ### By severity (time-to-detect, seconds after true onset)
65
+
66
+ | Severity | Mass-balance mean / median TTD | LSTM-AE mean / median TTD |
67
+ |---|---:|---:|
68
+ | Small (1-3% of flow) | 91.25 / 82.5 | 50.0 / 52.5 |
69
+ | Medium (3-8% of flow) | 66.25 / 70.0 | 43.1 / 42.5 |
70
+ | Large (8-20% of flow) | 52.5 / 52.5 | 30.6 / 35.0 |
71
+
72
+ Both detectors reach **100% detection on every severity band** on the 54 held-out test episodes (8-8-8
73
+ per severity among the 24 test leak episodes) — but note the dataset is a controlled, low-instrumentation-noise
74
+ simulation; see `published_baselines` in `eval_results.json` for how real fielded systems' sensitivity
75
+ varies (often 0.5-40% of flow depending on sensor spacing and instrumentation quality).
76
+
77
+ ## Best-effort NPW leak localization
78
+
79
+ Standard negative-pressure-wave time-of-arrival technique (textbook pipeline-engineering method, not a
80
+ vendor's proprietary algorithm): cross-correlating high-pass-filtered inlet/outlet pressure around the
81
+ detection time estimates the arrival-time difference `dt`, and `location_km_from_inlet = 0.5*(L + c*dt)`.
82
+ Evaluated on all 24 test leak episodes (using the primary mass-balance detector's alarm time as the trigger):
83
+
84
+ | | Mean abs. error (km) | Median abs. error (km) |
85
+ |---|---:|---:|
86
+ | **Overall** (pipe length 60 km) | 13.37 | 8.43 |
87
+ | Small leaks | 12.68 | 15.27 |
88
+ | Medium leaks | 13.72 | 7.88 |
89
+ | Large leaks | 13.72 | 5.78 |
90
+
91
+ **This is explicitly best-effort/demo-grade, reported honestly including the cases where it does not work
92
+ well** — accuracy is meaningfully worse for small leaks (weak signal-to-noise for the pressure transient)
93
+ than for large ones. A real deployment would need a much better-instrumented, higher-sample-rate pressure
94
+ system and a calibrated wave speed to get field-grade localization accuracy.
95
+
96
+ ## Files
97
+
98
+ - `lstm_ae.onnx` / `lstm_ae.pt` — LSTM-Autoencoder (encoder LSTM → latent → MLP decoder, same architecture
99
+ family as `refineryguard-lstm-ae`); ONNX used for CPU inference in the Space.
100
+ - `scaler.joblib` — `StandardScaler` fit on the 4 detector columns from normal-only train episodes.
101
+ - `mass_balance_config.joblib` — calibrated `(window, persist, mu, sigma, k)` for the mass-balance detector.
102
+ - `thresholds.joblib` — LSTM-AE reconstruction-error alarm threshold (99th percentile of a held-out normal
103
+ calibration split, never seen during gradient training).
104
+ - `eval_results.json` / `manifest.json` — full reproducible evaluation protocol and dataset manifest.
105
+
106
+ ## Reproducibility note
107
+
108
+ The mass-balance detector's numbers above are exactly reproducible (`python scripts/run_pipeline.py`
109
+ regenerates them bit-for-bit given the fixed seed). The LSTM-AE's numbers have minor run-to-run
110
+ floating-point jitter from PyTorch's multi-threaded CPU kernels even with all seeds fixed — the qualitative
111
+ finding (faster detection, higher false-alarm rate than mass-balance) is stable across reruns, but exact
112
+ decimals may shift by a few percent.
113
+
114
+ ## Related
115
+
116
+ - Dataset: [alirezaaminzadeh/pipelinewatch-scada-synthetic](https://huggingface.co/datasets/alirezaaminzadeh/pipelinewatch-scada-synthetic)
117
+ - Space: [alirezaaminzadeh/pipelinewatch-leak-detection](https://huggingface.co/spaces/alirezaaminzadeh/pipelinewatch-leak-detection)
118
+ - Sibling anomaly-detection projects: [alirezaaminzadeh/refineryguard-lstm-ae](https://huggingface.co/alirezaaminzadeh/refineryguard-lstm-ae), [alirezaaminzadeh/rotaguard-rul-lstm](https://huggingface.co/alirezaaminzadeh/rotaguard-rul-lstm)
119
+ - Product: [aria-ai.ir](https://aria-ai.ir)
120
+
121
+ MIT · Aria AI Engineering Team
eval_results.json ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "protocol": {
3
+ "honesty": "100% synthetic hydraulic/SCADA simulation (see src/pipelinewatch/simulate.py). Pipeline length (60 km), pressure-wave speed (1.1 km/s), and the friction/pressure relationship are ASSUMED textbook-typical values -- NOT calibrated to any real, named pipeline or customer asset. A real pilot deployment must replace/calibrate these constants against actual SCADA historian data from the specific line before any number below, especially the NPW localization error, is trusted for field use.",
4
+ "n_episodes": 180,
5
+ "n_train_episodes": 126,
6
+ "n_test_episodes": 54,
7
+ "sample_interval_s": 5,
8
+ "severity_bands_pct_of_nominal_flow": {
9
+ "small": [
10
+ 1,
11
+ 3
12
+ ],
13
+ "medium": [
14
+ 3,
15
+ 8
16
+ ],
17
+ "large": [
18
+ 8,
19
+ 20
20
+ ]
21
+ },
22
+ "mass_balance_calibration": {
23
+ "window_samples": 36,
24
+ "persist_windows": 6,
25
+ "k": 3.0,
26
+ "threshold": 1.7525218250941839,
27
+ "note": "mu/sigma/k calibrated on normal-only TRAIN episodes only; detection_rate/false_alarm below is measured on held-out TEST episodes."
28
+ }
29
+ },
30
+ "mass_balance": {
31
+ "small": {
32
+ "n_episodes": 8,
33
+ "detection_rate": 1.0,
34
+ "mean_ttd_s": 91.25,
35
+ "median_ttd_s": 82.5
36
+ },
37
+ "medium": {
38
+ "n_episodes": 8,
39
+ "detection_rate": 1.0,
40
+ "mean_ttd_s": 66.25,
41
+ "median_ttd_s": 70.0
42
+ },
43
+ "large": {
44
+ "n_episodes": 8,
45
+ "detection_rate": 1.0,
46
+ "mean_ttd_s": 52.5,
47
+ "median_ttd_s": 52.5
48
+ },
49
+ "overall": {
50
+ "n_episodes": 24,
51
+ "detection_rate": 1.0,
52
+ "mean_ttd_s": 70.0,
53
+ "median_ttd_s": 67.5
54
+ },
55
+ "false_alarm": {
56
+ "n_normal_episodes": 30,
57
+ "episodes_with_false_alarm_fraction": 0.16666666666666666,
58
+ "mean_false_alarms_per_hour": 0.3557202408522464
59
+ }
60
+ },
61
+ "lstm_ae": {
62
+ "small": {
63
+ "n_episodes": 8,
64
+ "detection_rate": 1.0,
65
+ "mean_ttd_s": 50.0,
66
+ "median_ttd_s": 52.5
67
+ },
68
+ "medium": {
69
+ "n_episodes": 8,
70
+ "detection_rate": 1.0,
71
+ "mean_ttd_s": 43.125,
72
+ "median_ttd_s": 42.5
73
+ },
74
+ "large": {
75
+ "n_episodes": 8,
76
+ "detection_rate": 1.0,
77
+ "mean_ttd_s": 30.625,
78
+ "median_ttd_s": 35.0
79
+ },
80
+ "overall": {
81
+ "n_episodes": 24,
82
+ "detection_rate": 1.0,
83
+ "mean_ttd_s": 41.25,
84
+ "median_ttd_s": 40.0
85
+ },
86
+ "false_alarm": {
87
+ "n_normal_episodes": 30,
88
+ "episodes_with_false_alarm_fraction": 0.7,
89
+ "mean_false_alarms_per_hour": 3.8418079096045186
90
+ },
91
+ "training_history": {
92
+ "best_val_mse": 0.03187253326177597,
93
+ "epochs_ran": 25.0
94
+ },
95
+ "threshold": 0.0505700446665287,
96
+ "window_samples": 36
97
+ },
98
+ "npw_localization": {
99
+ "n_localized": 24,
100
+ "mean_abs_error_km": 13.373748620341866,
101
+ "median_abs_error_km": 8.42794804230748,
102
+ "by_severity": {
103
+ "small": {
104
+ "n": 8,
105
+ "mean_abs_error_km": 12.681819882133222,
106
+ "median_abs_error_km": 15.265277817152366
107
+ },
108
+ "medium": {
109
+ "n": 8,
110
+ "mean_abs_error_km": 13.716801975487986,
111
+ "median_abs_error_km": 7.878984101297062
112
+ },
113
+ "large": {
114
+ "n": 8,
115
+ "mean_abs_error_km": 13.722624003404391,
116
+ "median_abs_error_km": 5.783308992666312
117
+ }
118
+ },
119
+ "method": "Cross-correlation of high-pass-filtered inlet/outlet pressure around the detection time; location_km_from_inlet = 0.5*(L + c*dt).",
120
+ "based_on_detector": "mass_balance",
121
+ "caveat": "Best-effort/demo-grade estimator, not a calibrated field system. Accuracy degrades substantially for small leaks (weak signal-to-noise) -- see by_severity breakdown."
122
+ },
123
+ "primary_detector": "mass_balance",
124
+ "primary_detector_rationale": "detection_rate tied (1.00); mass_balance has a lower false-alarm rate (0.36/h vs lstm_ae 3.84/h) on held-out normal test episodes, so it is recommended as the primary/first-line trigger. lstm_ae detects leaks faster on average (lower time-to-detect) and is recommended as a fast corroborating secondary signal, not as the sole trigger, given its higher false-alarm rate on this synthetic data.",
125
+ "published_baselines": [
126
+ {
127
+ "method": "Statistical volume/mass balance LDS (field deployment survey)",
128
+ "finding": "Reported sensitivity/response ranges from a 0.5% leak detected within 5 minutes on a short, well-instrumented segment, down to a 12% leak in 180 minutes on a >400 km large-separation offshore segment (sensitivity is strongly limited by sensor spacing and transient operations, not a single fixed number).",
129
+ "citation": "Atmosi, 'The challenges for effective leak detection on large diameter pipelines' (field deployment case studies). https://www.atmosi.com/us/news-events/blogs/the-challenges-for-effective-leak-detection-on-large-diameter-pipelines/"
130
+ },
131
+ {
132
+ "method": "Mass-balance leak detection with packing-term correction (transient flow)",
133
+ "finding": "Detection threshold of about 3% of mass flow over several minutes, contingent on pressure-wave-velocity uncertainty being minimized.",
134
+ "citation": "Pipeline leak detection based on mass balance: Importance of the packing term (transient-flow mass-balance LDS study). https://www.academia.edu/17624416/Pipeline_leak_detection_based_on_mass_balance_Importance_of_the_packing_term"
135
+ },
136
+ {
137
+ "method": "Unsupervised autoencoder-integrated model (TKAN-AE) on real urban pipeline field data",
138
+ "finding": "93.1% segment-wise precision detecting simulated leaks injected into real urban water-pipeline SCADA data (Shanghai field experiments).",
139
+ "citation": "Temporal Kolmogorov-Arnold Network with Autoencoder Integration for unsupervised pipeline leak detection. Sensors 2025, 25(2), 384. https://www.mdpi.com/1424-8220/25/2/384"
140
+ }
141
+ ],
142
+ "pipeline_seconds": 113.9
143
+ }
lstm_ae.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:428adaf82d5d1aac019a60d1f623c9a6d6b8dbeaca1ded194e4f4134defd02ea
3
+ size 43676
lstm_ae.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:04024a74b30aa6d832b8e65801f367bef71a5b185b3b452f4be5544b6e159366
3
+ size 44293
manifest.json ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "pipelinewatch-scada-synthetic",
3
+ "source": "100% synthetic hydraulic/SCADA simulation -- no real pipeline, historian, or customer data.",
4
+ "n_episodes": 180,
5
+ "n_samples_per_episode": 2160,
6
+ "sample_interval_s": 5,
7
+ "columns": [
8
+ "t_s",
9
+ "inlet_flow_m3h",
10
+ "outlet_flow_m3h",
11
+ "inlet_pressure_kpa",
12
+ "outlet_pressure_kpa",
13
+ "temperature_c",
14
+ "episode_id",
15
+ "leak_active",
16
+ "leak_rate_pct",
17
+ "leak_location_km",
18
+ "leak_severity_class"
19
+ ],
20
+ "detector_columns": [
21
+ "inlet_flow_m3h",
22
+ "outlet_flow_m3h",
23
+ "inlet_pressure_kpa",
24
+ "outlet_pressure_kpa"
25
+ ],
26
+ "severity_bands_pct_of_nominal_flow": {
27
+ "small": [
28
+ 1,
29
+ 3
30
+ ],
31
+ "medium": [
32
+ 3,
33
+ 8
34
+ ],
35
+ "large": [
36
+ 8,
37
+ 20
38
+ ]
39
+ },
40
+ "train_episode_ids": [
41
+ 0,
42
+ 1,
43
+ 2,
44
+ 3,
45
+ 4,
46
+ 5,
47
+ 6,
48
+ 8,
49
+ 9,
50
+ 11,
51
+ 14,
52
+ 15,
53
+ 16,
54
+ 17,
55
+ 18,
56
+ 19,
57
+ 21,
58
+ 23,
59
+ 24,
60
+ 25,
61
+ 26,
62
+ 27,
63
+ 29,
64
+ 31,
65
+ 32,
66
+ 33,
67
+ 34,
68
+ 35,
69
+ 37,
70
+ 38,
71
+ 40,
72
+ 42,
73
+ 43,
74
+ 44,
75
+ 46,
76
+ 48,
77
+ 49,
78
+ 50,
79
+ 51,
80
+ 52,
81
+ 53,
82
+ 54,
83
+ 55,
84
+ 56,
85
+ 57,
86
+ 58,
87
+ 62,
88
+ 64,
89
+ 65,
90
+ 66,
91
+ 67,
92
+ 68,
93
+ 69,
94
+ 70,
95
+ 71,
96
+ 72,
97
+ 74,
98
+ 76,
99
+ 77,
100
+ 79,
101
+ 80,
102
+ 83,
103
+ 87,
104
+ 88,
105
+ 90,
106
+ 93,
107
+ 94,
108
+ 95,
109
+ 98,
110
+ 101,
111
+ 103,
112
+ 104,
113
+ 105,
114
+ 106,
115
+ 107,
116
+ 108,
117
+ 110,
118
+ 111,
119
+ 112,
120
+ 113,
121
+ 116,
122
+ 117,
123
+ 118,
124
+ 119,
125
+ 120,
126
+ 121,
127
+ 122,
128
+ 124,
129
+ 126,
130
+ 127,
131
+ 128,
132
+ 129,
133
+ 130,
134
+ 131,
135
+ 132,
136
+ 133,
137
+ 136,
138
+ 137,
139
+ 138,
140
+ 139,
141
+ 141,
142
+ 142,
143
+ 143,
144
+ 144,
145
+ 146,
146
+ 150,
147
+ 152,
148
+ 154,
149
+ 155,
150
+ 158,
151
+ 159,
152
+ 160,
153
+ 161,
154
+ 162,
155
+ 163,
156
+ 164,
157
+ 165,
158
+ 166,
159
+ 169,
160
+ 171,
161
+ 172,
162
+ 174,
163
+ 176,
164
+ 177,
165
+ 178,
166
+ 179
167
+ ],
168
+ "test_episode_ids": [
169
+ 7,
170
+ 10,
171
+ 12,
172
+ 13,
173
+ 20,
174
+ 22,
175
+ 28,
176
+ 30,
177
+ 36,
178
+ 39,
179
+ 41,
180
+ 45,
181
+ 47,
182
+ 59,
183
+ 60,
184
+ 61,
185
+ 63,
186
+ 73,
187
+ 75,
188
+ 78,
189
+ 81,
190
+ 82,
191
+ 84,
192
+ 85,
193
+ 86,
194
+ 89,
195
+ 91,
196
+ 92,
197
+ 96,
198
+ 97,
199
+ 99,
200
+ 100,
201
+ 102,
202
+ 109,
203
+ 114,
204
+ 115,
205
+ 123,
206
+ 125,
207
+ 134,
208
+ 135,
209
+ 140,
210
+ 145,
211
+ 147,
212
+ 148,
213
+ 149,
214
+ 151,
215
+ 153,
216
+ 156,
217
+ 157,
218
+ 167,
219
+ 168,
220
+ 170,
221
+ 173,
222
+ 175
223
+ ]
224
+ }
mass_balance_config.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dc804985da49473fc694cc5679425fd217d6fc0a0fd402f5e322eb0863e5a7a3
3
+ size 135
scaler.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cddb809cf0fcc7a8ebfd73dcdd9be652bde677052b629db6f4a2c61f031e483c
3
+ size 711
thresholds.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ceab790a5fed799d4b9e73fd414f6337b85e03bb683874a4524d3bb040d19b09
3
+ size 34