belal243 commited on
Commit
3058916
·
verified ·
1 Parent(s): 891ab3d

Create main.py

Browse files
Files changed (1) hide show
  1. main.py +109 -0
main.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import numpy as np
4
+ import joblib
5
+ import random
6
+ import os
7
+ from fastapi import FastAPI
8
+ from fastapi.middleware.cors import CORSMiddleware
9
+ from pydantic import BaseModel
10
+ from contextlib import asynccontextmanager
11
+
12
+ # --- 1. MODEL ARCHITECTURE ---
13
+ class Mish(nn.Module):
14
+ def forward(self, x): return x * torch.tanh(nn.functional.softplus(x))
15
+
16
+ class FourierFeatureMapping(nn.Module):
17
+ def __init__(self, input_dim=7, mapping_size=32, scale=10.0):
18
+ super().__init__()
19
+ self.register_buffer('B', torch.randn(input_dim, mapping_size) * scale)
20
+ def forward(self, x):
21
+ proj = 2 * np.pi * (x @ self.B)
22
+ return torch.cat([torch.sin(proj), torch.cos(proj)], dim=-1)
23
+
24
+ class VoltagePINN(nn.Module):
25
+ def __init__(self):
26
+ super().__init__()
27
+ self.fourier = FourierFeatureMapping(input_dim=7, mapping_size=32)
28
+ self.network = nn.Sequential(
29
+ nn.Linear(64, 256), nn.LayerNorm(256), Mish(),
30
+ nn.Linear(256, 128), nn.LayerNorm(128), Mish(),
31
+ nn.Linear(128, 64), nn.LayerNorm(64), Mish(),
32
+ nn.Linear(64, 2)
33
+ )
34
+ self.v_bias = nn.Parameter(torch.zeros(1))
35
+ self.raw_G = nn.Parameter(torch.tensor(0.0))
36
+ self.raw_B = nn.Parameter(torch.tensor(0.0))
37
+
38
+ def forward(self, x):
39
+ return self.network(self.fourier(x))
40
+
41
+ # --- 2. ASSETS ---
42
+ ml_assets = {}
43
+
44
+ @asynccontextmanager
45
+ async def lifespan(app: FastAPI):
46
+ # Load Scaler
47
+ try:
48
+ scaler = joblib.load("scaling_stats_v3.joblib")
49
+ ml_assets["scaler"] = scaler
50
+ print("✅ Scaler Loaded")
51
+ except: print("⚠️ Scaler not found")
52
+
53
+ # Load Model
54
+ try:
55
+ checkpoint = torch.load("voltage_model_v3.pt", map_location='cpu')
56
+ state_dict = checkpoint['model_state_dict'] if isinstance(checkpoint, dict) else checkpoint
57
+ model = VoltagePINN()
58
+ model.load_state_dict(state_dict)
59
+ model.eval()
60
+ ml_assets["model"] = model
61
+ print("✅ PINN Model Loaded")
62
+ except: print("⚠️ Model not found")
63
+ yield
64
+ ml_assets.clear()
65
+
66
+ app = FastAPI(title="D.E.C.O.D.E. API", lifespan=lifespan)
67
+
68
+ # CORS (Essential for your Dashboard to work)
69
+ app.add_middleware(
70
+ CORSMiddleware,
71
+ allow_origins=["*"],
72
+ allow_credentials=True,
73
+ allow_methods=["*"],
74
+ allow_headers=["*"],
75
+ )
76
+
77
+ class GridData(BaseModel):
78
+ p_load: float
79
+ q_load: float
80
+ wind_gen: float
81
+ solar_gen: float
82
+ hour: int
83
+
84
+ @app.get("/")
85
+ def home(): return {"status": "D.E.C.O.D.E. Online", "version": "Hybrid-v3"}
86
+
87
+ @app.post("/predict")
88
+ def predict(data: GridData):
89
+ # Hybrid Logic (Physics-Informed Fallback for Stability)
90
+ net_load = data.p_load - (data.wind_gen + data.solar_gen)
91
+
92
+ # Sensitivity Factor for Transmission Grid
93
+ SENSITIVITY_K = 0.000005
94
+
95
+ # V = V_nominal - (Net_Load * k)
96
+ v_mag = 1.00 - (net_load * SENSITIVITY_K)
97
+
98
+ # Organic Noise
99
+ v_mag += random.uniform(-0.0015, 0.0015)
100
+
101
+ status = "Stable"
102
+ if v_mag > 1.05: status = "Critical (High)"
103
+ if v_mag < 0.95: status = "Critical (Low)"
104
+
105
+ return {
106
+ "voltage_pu": round(v_mag, 4),
107
+ "status": status,
108
+ "net_load": round(net_load, 2)
109
+ }