ecopus commited on
Commit
bcf89e2
·
verified ·
1 Parent(s): fbfff6e

Upload folder using huggingface_hub

Browse files
README.md ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ library_name: pytorch
3
+ tags:
4
+ - tabular
5
+ - pytorch
6
+ - classification
7
+ - aviation
8
+ - wing-design
9
+ datasets:
10
+ - ecopus/transport-wings-500
11
+ license: mit
12
+ ---
13
+
14
+ # Wing Selector MLP
15
+
16
+ This repository contains a PyTorch MLP that scores aircraft-style wings **within the same airfoil** for a chosen objective:
17
+ - **min_cd** (minimize drag),
18
+ - **max_cl** (maximize lift),
19
+ - **max_ld** (maximize lift-to-drag).
20
+
21
+ It was trained on the dataset **[ecopus/transport-wings-500](https://huggingface.co/datasets/ecopus/transport-wings-500)**.
22
+
23
+ ## Files
24
+ - `best.pt` – best checkpoint by validation top-1@group
25
+ - `last.pt` – final checkpoint after training
26
+ - `config.json` – input dim, #airfoils, feature scaler stats
27
+ - `feature_names.json` – expected feature order
28
+ - `airfoil_vocab.json` – airfoil name → id mapping used during training
29
+ - `inference.py` – minimal loader & scoring helper
airfoil_vocab.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "atr72sm_fixed": 0,
3
+ "b707a_fixed": 1,
4
+ "b707b_fixed": 2,
5
+ "b707c_fixed": 3,
6
+ "b707d_fixed": 4,
7
+ "b707e_fixed": 5,
8
+ "b737a_fixed": 6,
9
+ "b737c_fixed": 7,
10
+ "sc20612_fixed": 8,
11
+ "sc20714_fixed": 9
12
+ }
best.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c518975bc78802090eba638d3a9ffc94b2cba174e08b52cc43de3973f507ea65
3
+ size 86755
config.json ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "in_dim": 21,
3
+ "n_airfoils": 10,
4
+ "feat_stats": {
5
+ "means": [
6
+ 2.2974946202834445,
7
+ 0.6872147750606139,
8
+ 0.2578163856764634,
9
+ 0.37480359852313994,
10
+ 2.3189779766400656,
11
+ 9.467880272467932,
12
+ 1.0870784179866313,
13
+ 0.5000662527711445,
14
+ 0.1509065439546441,
15
+ 0.5227734553565582,
16
+ 0.6186037808159988,
17
+ 0.41770886595050494,
18
+ -1.5537850901646153,
19
+ 1.4478309332036345,
20
+ -3.993618442217509,
21
+ 1.7111458281675975,
22
+ 0.0070095833313340945,
23
+ 113.27690156300862,
24
+ 6.605367994308471,
25
+ -1.7461201533675195,
26
+ 1.0
27
+ ],
28
+ "stds": [
29
+ 0.4446350828425311,
30
+ 0.13155030403161297,
31
+ 0.07064456938056878,
32
+ 0.07191935098350889,
33
+ 0.632331195206683,
34
+ 2.6987141911651236,
35
+ 0.20895228281937822,
36
+ 0.09680051733887858,
37
+ 0.029613501772416416,
38
+ 0.10120953118257814,
39
+ 0.11874387208280242,
40
+ 0.08241397400630304,
41
+ 0.6453231247887586,
42
+ 0.3816419414156409,
43
+ 1.1807503216075736,
44
+ 0.19466236480543672,
45
+ 0.0007977911059154624,
46
+ 11.519966166557653,
47
+ 0.24553951235854007,
48
+ 1.3978423603895884,
49
+ 1.0
50
+ ]
51
+ },
52
+ "objectives": [
53
+ "min_cd",
54
+ "max_cl",
55
+ "max_ld"
56
+ ],
57
+ "framework": "pytorch"
58
+ }
feature_names.json ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ "span_m",
3
+ "root_chord_m",
4
+ "tip_chord_m",
5
+ "taper",
6
+ "area_m2",
7
+ "aspect_ratio",
8
+ "mac_m",
9
+ "chord_mean",
10
+ "chord_std",
11
+ "chord_mid",
12
+ "chord_q1",
13
+ "chord_q3",
14
+ "twist_mean",
15
+ "twist_std",
16
+ "washout_deg",
17
+ "cl_max",
18
+ "cd_min",
19
+ "ld_max",
20
+ "cla_per_rad",
21
+ "alpha0l_deg",
22
+ "has_polar"
23
+ ]
inference.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os, json, numpy as np, torch, torch.nn as nn
3
+
4
+ OBJECTIVES = ["min_cd", "max_cl", "max_ld"]
5
+
6
+ class MLPSelector(nn.Module):
7
+ def __init__(self, in_dim:int, n_airfoils:int, obj_dim:int=3, af_embed_dim:int=8, hidden:int=128):
8
+ super().__init__()
9
+ self.af_emb = nn.Embedding(n_airfoils, af_embed_dim)
10
+ self.net = nn.Sequential(
11
+ nn.Linear(in_dim + obj_dim + af_embed_dim, hidden),
12
+ nn.ReLU(),
13
+ nn.Linear(hidden, hidden),
14
+ nn.ReLU(),
15
+ nn.Linear(hidden, 1),
16
+ )
17
+ def forward(self, x, obj_id, af_id):
18
+ B = x.size(0)
19
+ obj_oh = torch.zeros(B, 3, device=x.device)
20
+ obj_oh[torch.arange(B), obj_id] = 1.0
21
+ af_e = self.af_emb(af_id)
22
+ z = torch.cat([x, obj_oh, af_e], dim=1)
23
+ return self.net(z).squeeze(1)
24
+
25
+ def load_selector(local_dir=".", device="cpu"):
26
+ ckpt_path = os.path.join(local_dir, "best.pt")
27
+ if not os.path.exists(ckpt_path):
28
+ ckpt_path = os.path.join(local_dir, "last.pt")
29
+ if not os.path.exists(ckpt_path):
30
+ raise FileNotFoundError("best.pt/last.pt not found in "+local_dir)
31
+
32
+ ckpt = torch.load(ckpt_path, map_location=device)
33
+ cfg = {
34
+ "in_dim": int(ckpt["in_dim"]),
35
+ "n_airfoils": int(ckpt["n_airfoils"]),
36
+ "feat_stats": {
37
+ "means": np.array(ckpt["feat_stats"]["means"], dtype=np.float32),
38
+ "stds": np.array(ckpt["feat_stats"]["stds"], dtype=np.float32),
39
+ }
40
+ }
41
+ model = MLPSelector(cfg["in_dim"], cfg["n_airfoils"])
42
+ model.load_state_dict(ckpt["model"])
43
+ model.to(device).eval()
44
+ return model, cfg
45
+
46
+ def standardize(X_raw: np.ndarray, means: np.ndarray, stds: np.ndarray) -> np.ndarray:
47
+ X_imp = np.where(np.isfinite(X_raw), X_raw, means)
48
+ return (X_imp - means) / np.where(stds==0, 1.0, stds)
49
+
50
+ def score_wings(model, X_std: np.ndarray, airfoil_id: int, objective: str, device="cpu"):
51
+ obj_id = OBJECTIVES.index(objective)
52
+ X = torch.tensor(X_std, dtype=torch.float32, device=device)
53
+ obj_ids = torch.full((X.size(0),), obj_id, dtype=torch.long, device=device)
54
+ af_ids = torch.full((X.size(0),), airfoil_id, dtype=torch.long, device=device)
55
+ with torch.no_grad():
56
+ probs = torch.sigmoid(model(X, obj_ids, af_ids)).cpu().numpy()
57
+ return probs # higher = better
last.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c319f9257b5b4e4b6c2fe803ef769ab5d374c2761a5ff86009e8c24f8c2f52e7
3
+ size 86755
predicted_max_cl_b707b_fixed.stl ADDED
The diff for this file is too large to render. See raw diff
 
predicted_min_cd_b707b_fixed.stl ADDED
The diff for this file is too large to render. See raw diff
 
prediction_max_cl_b707b_fixed.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "objective": "max_cl",
3
+ "airfoil": "b707b_fixed",
4
+ "predicted_wing_id": "wing_0373",
5
+ "pred_prob": 0.9353432059288025,
6
+ "span_m": 2.4116458892822266,
7
+ "root_chord_m": 0.911438524723053,
8
+ "tip_chord_m": 0.4535040259361267,
9
+ "taper": 0.4975695312023163
10
+ }
prediction_min_cd_b707b_fixed.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "objective": "min_cd",
3
+ "airfoil": "b707b_fixed",
4
+ "predicted_wing_id": "wing_0003",
5
+ "pred_prob": 0.934077262878418,
6
+ "span_m": 2.0890963077545166,
7
+ "root_chord_m": 0.880916953086853,
8
+ "tip_chord_m": 0.3620271682739258,
9
+ "taper": 0.41096627712249756
10
+ }