FloodGuard — Dam Management & Early-Warning System

FloodGuard is an advanced, real-time reservoir monitoring and predictive flood-risk decision-support system. Designed for critical infrastructure management, the platform ingests live sensor telemetry, performs high-resolution divided-difference forecasts, computes dynamic safety thresholds, and provides proportional gate-release recommendations for on-site engineers—warning of hazardous states hours before they manifest.

This repository hosts the canonical PostgreSQL database schema, the core calculation engine algorithms, the Next.js integration APIs, and a graphical weather simulation suite.


Table of Contents


Team


Table of Contents

  1. Project Overview
  2. System Architecture
  3. PostgreSQL Database System Schema (3NF)
  4. Calculation Reference & Predictive Algorithm
  5. Machine Learning Integration Contract
  6. Simulation & Testing Scenarios
  7. Getting Started
  8. Links

1. Project Overview

Traditional dam safety protocols rely on static water-level thresholds. If a reservoir level crosses a fixed limit (e.g., 85%), gates are opened. However, under extreme storm conditions, the time required for physical gate configuration and downstream channel evacuation can exceed the safe response window.

FloodGuard implements a predictive, adaptive-threshold model where risk is assessed dynamically based on:

Rather than waiting for a breach, the system extrapolates historical trends forward, identifies if and when the predicted water level will cross the predicted safety threshold (the Time-To-Crossing or TTC), and triggers alarms in advance.


2. System Architecture

flowchart LR
    subgraph Field["Field Sensor & Simulation Layer"]
        S1[Water Level Sensor]
        S2[Meteorological Station Sensors]
        S3[Upstream Inflow Sensor]
        S4[Downstream Level Sensor]
        SIM[Tkinter Weather Simulator]
    end

    subgraph Pred["Prediction & Calculation Layer"]
        ALGO[Reference Mathematical Engine<br/>or Trained ML Model]
    end

    subgraph DB["PostgreSQL Database (Local)"]
        WL[(water_level_readings)]
        RF[(rainfall_readings)]
        IF[(inflow_readings)]
        DL[(downstream_level_readings)]
        CM[(calculated_metrics)]
        TC[(threshold_calculations)]
        RS[(risk_status)]
        RR[(release_recommendations)]
        DT[(deescalation_tracking)]
        AL[(alerts_log)]
    end

    subgraph FE["Frontend Dashboard"]
        DASH[SCADA Operator UI]
    end

    S1 --> WL
    S2 --> RF
    S3 --> IF
    S4 --> DL
    SIM --> WL & RF & IF & DL
    
    WL & RF & IF & DL --> ALGO
    ALGO --> CM --> TC --> RS
    RS --> RR
    RS --> DT
    RS --> AL
    
    WL & CM & TC & RS & RR & AL --> DASH

The system operates on an event-driven and polling pipeline:

  1. Sensor Ingestion: Telemetry is written to the database.
  2. Processor Loop: Evaluates new raw telemetry, computes metrics and thresholds, checks predictive crossing models, and determines risk states.
  3. Frontend Refresh: Next.js API layer serves data, refreshing the SCADA panel dynamically on a 15-second polling interval.

3. PostgreSQL Database System Schema (3NF)

The database schema is fully normalized to Third Normal Form (3NF) to support transactional integrity and clean time-series storage.

3.1 Static Configuration Tables

dams

Holds physical limits, capacities, and baseline calibration thresholds for each dam.

engineers

System user profiles for dam operator logs and alert acknowledgements.

rainfall_locations

Catchment meteorological stations associated with the dam.


3.2 Live Time-Series Sensor Tables (3NF)

water_level_readings

inflow_readings

downstream_level_readings

rainfall_readings


3.3 Backend Prediction & Calculation Tables

prediction_runs

Records metadata for each divided-difference forecast run.

predicted_values

Contains extrapolated future states across forecast horizons ($t+15$ to $t+120$ mins).

graph_crossing_results

Stores summary predictions on threshold crossings.

calculated_metrics

Intermediate calculations performed per sensor scan.

threshold_calculations

risk_status

Official alert state of the dam.

release_recommendations

Proportional gate release plans calculated for ORANGE or RED status.

deescalation_tracking

Maintains cumulative timers for de-escalation dampening.


4. Calculation Reference & Predictive Algorithm

The reference engine processes mathematical updates on every ingestion cycle (1-minute intervals during real-time telemetry, or 15-second intervals under simulator conditions).

4.1 Inflow, Level, & Runoff Inputs

The engine ingests:

Weighted Net Catchment Rainfall ($R_{net}$)

To account for geographic delays, rainfall runoff is modeled by looking back at station delay offsets ($\tau_i$). If a station has missing telemetry, weights are scaled dynamically:

\[R_{net}(t) = \frac{\sum w_i R_i(t - \tau_i)}{\sum w_{active}}\]

4.2 Rise Rate & Acceleration

Short-term Rise Rate ($RR_{short}$)

Measures water level rate of change over the last 15 minutes, scaled to an hourly rate:

\[RR_{short}(t) = [L(t) - L(t - 15)] \times 4 \quad (\%/hour)\]

Long-term Rise Rate ($RR_{long}$)

Measures change over the last 60 minutes:

\[RR_{long}(t) = [L(t) - L(t - 60)] \times 1 \quad (\%/hour)\]

Rise Rate Acceleration ($ACC$)

Measures the change in long-term rise rate over the preceding hour:

\[ACC(t) = RR_{long}(t) - RR_{long}(t - 60) \quad (\%/hour^2)\]

Rolling Average ($RA$) & Deviation Score ($DEV$)

Calculates the 3-hour moving average of the long-term rise rate and compares it to the short-term spike rate to identify flash surge anomalies:

\[RA(t) = \text{Average}(RR_{long}) \text{ over last 3 hours}\] \[DEV(t) = RR_{short}(t) - RA(t)\]

4.3 Severity Classifications (Bands)

Telemetry states are classified into four rise-rate severity bands. The worst individual parameter match determines the band.

Severity Band Long-Term Rise Rate Short-Term Rise Rate Acceleration
NORMAL $< 1.0\,\%/h$ AND $< 2.0\,\%/h$ AND $\le 0.5\,\%/h^2$
ELEVATED $1.0\text{–}2.5\,\%/h$ OR $2.0\text{–}4.0\,\%/h$ OR $0.5\text{–}1.5\,\%/h^2$
HIGH $2.5\text{–}4.0\,\%/h$ OR $4.0\text{–}7.0\,\%/h$ OR $1.5\text{–}3.0\,\%/h^2$
CRITICAL $> 4.0\,\%/h$ OR $> 7.0\,\%/h$ OR $> 3.0\,\%/h^2$ (or $DEV > 5.0$)

4.4 Adaptive Safety Threshold ($AT$)

The safety threshold shifts downwards from BASE (75%) depending on hydrological stresses, clamped at a minimum FLOOR (30%).

\[AT(t) = \text{Clamp}( L_{base} - rr_{adj} - rf_{adj} - if_{adj} - dl_{adj},\; L_{floor},\; L_{base} )\]

Individual Penalties

  1. Rise Rate Adjustment ($rr_{adj}$):
    • NORMAL: 0% ELEVATED: 8% HIGH: 18% CRITICAL: 30%
  2. Rainfall Adjustment ($rf_{adj}$):
    • $R_{net} < 10$: 0% $10\text{–}25$: 3% $25\text{–}50$: 7% $> 50\,\text{mm/h}$: 12%
  3. Inflow Adjustment ($if_{adj}$): (relative to baseline inflow $IF_{base}$)
    • $IF(t) < 1.5 \times IF_{base}$: 0% $1.5\text{–}2.5 \times$: 4% $2.5\text{–}4 \times$: 8% $> 4 \times IF_{base}$: 13%
  4. Downstream level Adjustment ($dl_{adj}$):
    • $DL < 50\%$: 0% $50\text{–}70\%$: 3% $70\text{–}85\%$: 8% $> 85\%$: 15%

4.5 Newton Divided-Difference Extrapolation

For prediction cycles, the engine fits a polynomial through recent historical readings to extrapolate water levels ($L_{pred}(t+h)$) and inflow rates ($IF_{pred}(t+h)$) for horizons $h \in {15, 30, 45, 60, 90, 120}$ minutes.

To avoid high-degree oscillations (Runge’s phenomenon), the engine selects a low-degree fit (linear or quadratic) using the last 3-4 historical data points spaced over a rolling 6-hour window.

Divided-Difference Table

Given nodes $(x_0, y_0), (x_1, y_1), \dots, (x_k, y_k)$, divided differences are defined recursively:

\[f[x_i] = y_i\] \[f[x_i, x_{i+1}, \dots, x_{i+j}] = \frac{f[x_{i+1}, \dots, x_{i+j}] - f[x_i, \dots, x_{i+j-1}]}{x_{i+j} - x_i}\]

The interpolating polynomial is:

\[P(x) = f[x_0] + \sum_{i=1}^k f[x_0, \dots, x_i] \prod_{j=0}^{i-1} (x - x_j)\]

4.6 Graph Crossing Analysis & Time-To-Crossing ($TTC$)

A crossing is predicted if the gap margin at any horizon $h$ falls to or below zero:

\[Gap(t+h) = AT_{pred}(t+h) - L_{pred}(t+h) \le 0\] \[\Delta Gap = Gap(t+h) - Gap(t+h-15)\]

4.7 Risk Status Classification Rules

Risk statuses are evaluated in order of severity. First match wins.

Risk Status Trigger Conditions
🔴 Red $L(t) \ge AT(t)$ (Current level exceeds safety threshold)
OR $TTC \le 15$ minutes (Crossing imminent)
OR $RR_{band} = \text{CRITICAL}$
🟠 Orange $L(t) \ge AT(t) + 3\%$ (Within 3% of threshold)
OR ($TTC \le 60$ minutes)
OR ($RR_{band} = \text{HIGH}$ AND Gap Trend = decreasing)
🟡 Yellow $L(t) \ge AT(t) + 10\%$ (Within 10% of threshold)
OR ($TTC > 60$ minutes)
OR ($RR_{band} = \text{ELEVATED}$)
OR ($TTC = \text{Null}$ AND Gap Trend = decreasing)
🟢 Green All other conditions

4.8 Proportional Release Recommendations

Calculated when risk status reaches ORANGE or RED.

  1. Calculate Volumetrically Desired Discharge ($Q_{desired}$): Calculates the release rate required to bring the reservoir down to the threshold level over the next hour:

    \[Q_{desired}(t) = IF(t) - \frac{(AT(t) - L(t)) \times \text{Capacity}_{reservoir}}{3600 \times 100} \quad (m^3/s)\]
  2. Downstream Safety Limit ($Q_{down_avail}$): Calculates the remaining capacity of the downstream channel:

    \[Q_{down\_avail}(t) = \text{Capacity}_{downstream} \times \left(1 - \frac{DL(t)}{100}\right) \quad (m^3/s)\]
  3. Apply Safety Overrides:

    \[Q_{release}(t) = \text{Min}\left(Q_{desired}(t),\; Q_{down\_avail}(t),\; \text{Capacity}_{max\_gate}\right)\]

    If $Q_{desired} > Q_{down_avail}$, a CONFLICT WARNING is flagged to inform operators that the downstream channel is constrained.

  4. Proportional Gate Opening:

    \[\text{GateOpening}\% = \left(\frac{Q_{release}(t)}{\text{Capacity}_{max\_gate}}\right) \times 100\]

    Rounded to the nearest 5% for operator configuration.

  5. Estimated Discharge Duration ($t_{duration}$): Calculates the duration (minutes) needed to lower the level to a target buffer level ($AT(t) - 10\%$):

    \[t_{duration} = \frac{L(t) - (AT(t) - 10.0)}{\left(\frac{Q_{release} - IF(t)}{\text{Capacity}_{reservoir}}\right) \times 100 \times 60} \quad \text{minutes}\]

4.9 Sustained De-escalation Timers

Status downgrades are delayed to prevent rapid toggling due to noise. The system must meet de-escalation rules continuously:


5. Machine Learning Integration Contract

The prediction layer is model-agnostic. The deterministic reference algorithm can be swapped for a trained ML model by satisfying this integration contract.

+------------------+       Reads telemetry       +------------------+
|   PostgreSQL     | --------------------------> |  Trained Model   |
|   Database       | <-------------------------- |  (Python Script) |
+------------------+    Writes predictions &     +------------------+
                            risk status

5.1 Inputs

The model must query live and historical time-series data directly from:

5.2 Outputs

The model must write its calculated predictions into the database tables:

  1. calculated_metrics: Populate rise rates, acceleration, rolling average, deviation, and rise rate band.
  2. threshold_calculations: Populate the calculated dynamic safety threshold and adjustments.
  3. risk_status: Set the calculated risk status.
  4. release_recommendations: Generate proportional gate openings and safe release rates.

6. Simulation & Testing Scenarios

The Tkinter weather simulator generates real-time telemetry to test system responses.


7. Getting Started

We have containerized the core infrastructure (PostgreSQL database, Python backend, and Next.js frontend) using Docker for a seamless setup experience. The simulation GUI runs on your local machine so it can easily display its interface.

7.1 Start Core Services

  1. Copy .env.example to .env:
    cp .env.example .env
    
  2. Build and start the infrastructure in the background:
    docker compose up -d --build
    

    This automatically sets up the PostgreSQL database with schemas and initial data, starts the backend processor, and serves the Next.js frontend on port 3000.

7.2 Access the Dashboard

Open your browser and navigate to http://localhost:3000 to view the SCADA control panel.

7.3 Run the Weather Simulator

Since the database container exposes port 5432, the Tkinter simulation GUI can run directly on your host machine and connect to it natively.

  1. Install Python dependencies:
    pip install -r requirements.txt
    
  2. Launch the simulator:
    python code/simulation/db_simulator.py