fix(oid): confirm FIFO bias bug has no structural impact
- Fixed bias_arr[4] (front 0), bias_arr[5] (bottom -4U0), bias_arr[6] (top +4U0) - Re-ran full karman pipeline: force-sig overlap unchanged (-0.034) - Force-OID still beats POD (0.295 vs 0.068, was 0.750 vs 0.418) - Absolute R2 shifted because corrected FIFO changed PPO trajectory start - Structural conclusion (force-sig near-orthogonal) is robust Co-authored-by: Cursor <cursoragent@cursor.com>
@@ -0,0 +1,144 @@
|
||||
# SR Analysis Pipeline
|
||||
|
||||
> Symbolic regression pipeline for extracting interpretable DRL control laws (obs → act) from the fluidic pinball.
|
||||
> Four independent stages: inference → fitting → validation → analysis.
|
||||
|
||||
## Pipeline Architecture
|
||||
|
||||
```
|
||||
[PPO 推理] [PySR 拟合] [CFD 验证] [分析/画图]
|
||||
stage_1_infer.py stage_2_fit.py stage_3_validate.py stage_4_analyze.py
|
||||
↓ ↓ ↓ ↓
|
||||
controlled.npz formulas/*.json validations/*.json data/figures/*.png
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Generate PPO data
|
||||
conda run -n pycuda_3_10 python stage_1_infer.py --scene karman_re100 --device 2
|
||||
|
||||
# 2. Fit PySR formula
|
||||
conda run -n sr_env python stage_2_fit.py --scene karman_re100 --mode per-scene
|
||||
|
||||
# 3. Validate in CFD
|
||||
conda run -n pycuda_3_10 python stage_3_validate.py \
|
||||
--scene karman_re100 --device 2 --mode pysr \
|
||||
--formula-front results/formulas/karman_re100_front.json \
|
||||
--formula-top results/formulas/karman_re100_top.json
|
||||
|
||||
# 4. Analyze results
|
||||
conda run -n pycuda_3_10 python stage_4_analyze.py --scene karman_re100 --mode ppo-viz
|
||||
```
|
||||
|
||||
## Environments
|
||||
|
||||
| Env | Used For |
|
||||
|-----|----------|
|
||||
| `pycuda_3_10` | Stage 1 (CFD inference), Stage 3 (CFD validation), Stage 4 (analysis) |
|
||||
| `sr_env` | Stage 2 (PySR symbolic regression) |
|
||||
|
||||
GPU: device 2 recommended (device 0 may conflict with PyTorch).
|
||||
|
||||
## Key Conventions
|
||||
|
||||
### Reynolds Number
|
||||
- Code Re uses reference length 2D = 40: `Re = U0 * 40 / nu`
|
||||
- Physical Re_D uses D = 20: `Re_D = Re / 2`
|
||||
- Default: Re_code=100 → Re_D=50, nu=0.004
|
||||
|
||||
### Action
|
||||
- `controlled.npz` stores actions as **normalized [-1, +1]** (not physical omega)
|
||||
- Physical omega: `omega = (action * scale + bias) * U0`, then divided by radius for angular velocity
|
||||
- Fitting target: **non-dimensional alpha = omega / U0** (not omega)
|
||||
|
||||
### Action Bias vs FIFO Bias
|
||||
- **DRL action decoder bias**: `action * scale + bias` → physical omega. Karman: [0,-4,4], Illusion: [0,-2,2], Vortex: [0,-4,4]
|
||||
- **FIFO initialization bias** (environment warmup): different values! Illusion FIFO uses [0, -U0, U0] (1U scale), not [0, -2U0, 2U0]
|
||||
|
||||
### Inlet
|
||||
- Parabolic velocity profile (not uniform). Top/bottom walls are no-slip bounce-back.
|
||||
- U0 = 0.01 at centerline (lattice units)
|
||||
|
||||
### G-mirror
|
||||
- Correct: `[aF, aT, aB] → [-aF, -aB, -aT]` (not the old buggy version)
|
||||
- v23 structure: Front no-bias (α_F = 0 when features = 0), rear shared-head (α_B = -Top∘G)
|
||||
|
||||
### Norm
|
||||
- Each scene computes its own force/sensor normalization during environment initialization
|
||||
- Must use the **same norm values** during inference and during validation
|
||||
- Norm values are saved in `norm.json` in each data directory
|
||||
|
||||
### Sample Interval & Steps
|
||||
| Scene | SI | Validation Steps |
|
||||
|-------|:--:|:----------------:|
|
||||
| Karman | 800 | 160-200 |
|
||||
| Illusion 0.75L | 400 | 320 |
|
||||
| Illusion 1L | 600 | 214 |
|
||||
| Illusion 1.5L | 800 | 160 |
|
||||
| Vortex | 800 | 150 (transient) |
|
||||
|
||||
Rule: steps ≥ NX/U0/SI = 1280/0.01/SI ≈ 128000/SI
|
||||
|
||||
## Results Index
|
||||
|
||||
All results indexed in [`scene_registry.json`](scene_registry.json). Canonical formulas in `results/formulas/`, CFD validations in `results/validations/`.
|
||||
|
||||
### Canonical Formulas
|
||||
|
||||
| Formula File | Scene | Formula |
|
||||
|-------------|-------|---------|
|
||||
| `results/formulas/karman_joint_front.json` | Karman cross-Re (joint) | `daF_dt - 14.952*mu*Cl_tot` |
|
||||
| `results/formulas/karman_joint_top.json` | Karman cross-Re (joint) | `3.414` (constant) |
|
||||
| `results/formulas/illusion_joint_front.json` | Illusion joint (0.75L+1L) | `Cd_tot - (Cd_err + 5.428) - 0.00978*(du_a_dt + u_a)` |
|
||||
| `results/formulas/illusion_joint_top.json` | Illusion joint (0.75L+1L) | `(Cd_err - (Cd_rear - Cl_err))*0.535 + 2.782` |
|
||||
|
||||
### Key CFD Results
|
||||
|
||||
| Scene | Formula | Similarity |
|
||||
|-------|---------|:----------:|
|
||||
| Karman cross-Re avg | Joint | 0.847 |
|
||||
| Illusion 0.75L | Joint | 0.978 |
|
||||
| Illusion 1L | Joint | 0.970 |
|
||||
| Vortex lamb | Karman joint | 0.949 (exceeds PPO 0.942) |
|
||||
| Illusion 0.6L | Joint (generalization) | 0.939 |
|
||||
| Illusion 0.8L | Joint (generalization) | 0.908 |
|
||||
| Illusion 1.2L | Joint (generalization) | 0.849 |
|
||||
| Illusion 2L | Joint (generalization) | 0.676 |
|
||||
|
||||
### Feature Sets
|
||||
|
||||
| Name | Features | Dim | Used For |
|
||||
|------|----------|:---:|----------|
|
||||
| PHASE_STATE_KEYS | u_a, du_a_dt, Cl_tot, dCl_tot_dt, Cd_tot, Cd_rear | 6 | Karman per-Re |
|
||||
| ILLUSION_PHASE_KEYS | phase-state + Cd_err, Cl_err, dCd_err_dt, dCl_err_dt | 10 | Illusion |
|
||||
| PHYS_DADT | physics + daF_dt, daB_dt, daT_dt + mu | 17 | Karman joint/deep |
|
||||
|
||||
## Key Documentation
|
||||
|
||||
| File | Content |
|
||||
|------|---------|
|
||||
| `PIPELINE.md` | This file — overview, environment, conventions |
|
||||
| `sindy_sr_knowledge.md` | Bug history, confirmed facts, known limitations |
|
||||
| `sindy_sr_notes.md` | Task list, current status |
|
||||
| `STAGE_1_INFER.md` | Stage 1: PPO data generation |
|
||||
| `STAGE_2_FIT.md` | Stage 2: PySR fitting |
|
||||
| `STAGE_3_VALIDATE.md` | Stage 3: CFD validation |
|
||||
| `STAGE_4_ANALYZE.md` | Stage 4: Analysis & visualization |
|
||||
| `docs/SR_analysis_report.md` | Full report (465+ lines) |
|
||||
| `docs/illusion_joint_formula_analysis.md` | Illusion joint formula deep dive |
|
||||
|
||||
## Stage 0 Audit (2026-06-28)
|
||||
|
||||
All imports verified in both conda environments:
|
||||
|
||||
| Script | pycuda_3_10 | sr_env |
|
||||
|--------|:-----------:|:------:|
|
||||
| `stage_1_infer.py` (infer_karman / infer_illusion / infer_vortex) | OK | — |
|
||||
| `stage_2_fit.py` (PySR) | — | OK |
|
||||
| `stage_3_validate.py` (closed-loop) | OK | — |
|
||||
| `stage_4_analyze.py` (analysis) | OK | — |
|
||||
| `core/features.py` (feature_builder) | OK | OK |
|
||||
| `core/cfd.py` (cfd_interface) | OK | — |
|
||||
|
||||
No broken imports. All dependencies available.
|
||||
@@ -4,181 +4,81 @@ Extracts interpretable control laws (`obs -> act`) from DRL-trained policies for
|
||||
fluidic pinball. Uses **PySR symbolic regression** on dimensionless physical features with
|
||||
G-equivariant structural constraints (v23: front no-bias, rear shared-head).
|
||||
|
||||
## Current Results (2026-06-25)
|
||||
## Quick Start
|
||||
|
||||
### Karman Cloak — Cross-Re Unified Formula
|
||||
```bash
|
||||
# 1. Generate PPO data
|
||||
conda run -n pycuda_3_10 python stage_1_infer.py --scene karman_re100 --device 2
|
||||
|
||||
| Scene | Front Formula | Top Formula | CFD Closed-Loop |
|
||||
|-------|--------------|-------------|:---------------:|
|
||||
| Joint (Re50-400) | `daF_dt - 14.952*mu*Cl_tot` | `alpha_T = 3.414` (const) | **0.847 avg** |
|
||||
| Re50 independent | PySR per-Re best | — | **0.895** |
|
||||
| Re100 independent | PySR per-Re best | — | **0.888** |
|
||||
| Re200 independent | PySR per-Re best | — | **0.916** |
|
||||
| Re400 (SI=400 opt) | Joint formula | Joint formula | **0.819** |
|
||||
# 2. Fit formula
|
||||
conda run -n sr_env python stage_2_fit.py --scene karman_re100 --mode per-scene
|
||||
|
||||
### Illusion
|
||||
# 3. Validate in CFD
|
||||
conda run -n pycuda_3_10 python stage_3_validate.py \\
|
||||
--scene karman_re100 --device 2 --mode pysr \\
|
||||
--formula-front results/formulas/karman_joint_front.json \\
|
||||
--formula-top results/formulas/karman_joint_top.json
|
||||
|
||||
| Scene | Front Formula | CFD Closed-Loop | % of PPO |
|
||||
|-------|--------------|:---------------:|:--------:|
|
||||
| 0.75L | `-0.169*(Cl_tot + dCl_tot_dt) - 1.240` | **0.979** | 100.7% |
|
||||
| 1L | `(du_a_dt + u_a + 26.5)*0.0123` | **0.957** | 98.4% |
|
||||
| **Joint (0.75L+1L)** | `target_Cd - 5.428 + 0.0098*(du_a_dt + u_a)` | **0.978 / 0.970** | — |
|
||||
| 1.5L | High-freq periodic modulation (not SR-amenable) | — | — |
|
||||
# 4. Analyze
|
||||
conda run -n pycuda_3_10 python stage_4_analyze.py --scene karman_re100 --mode ppo-viz
|
||||
```
|
||||
|
||||
**Key finding**: 0.75L and 1L formulas have fundamentally different skeletons (Cl_tot vs u_a
|
||||
dominant). Joint formula still achieves excellent CFD results on both although the underlying
|
||||
mechanisms differ.
|
||||
## Pipeline Architecture
|
||||
|
||||
### Illusion Generalization (Joint Formula, No PPO)
|
||||
```
|
||||
stage_1_infer.py → stage_2_fit.py → stage_3_validate.py → stage_4_analyze.py
|
||||
(PPO数据) (PySR拟合) (CFD闭环验证) (分析/画图)
|
||||
```
|
||||
|
||||
| Diameter | Similarity | Notes |
|
||||
|:--------:|:----------:|-------|
|
||||
| 0.5L | 0.854 | Signal weak, noise-dominated |
|
||||
| 0.6L | **0.939** | Generalizes well |
|
||||
| 0.8L | **0.908** | Generalizes well |
|
||||
| 1.2L | 0.849 | Begins to degrade |
|
||||
| 1.5L | N/A | High-frequency regime, different mechanism |
|
||||
| 2.0L | 0.676 | Degraded, near 1.5L regime |
|
||||
## Directory Structure
|
||||
|
||||
Valid range: 0.6L-1.0L (similarity > 0.90).
|
||||
|
||||
### Vortex Cloak (Generalization)
|
||||
|
||||
Karman joint formula tested on vortex scenes (no retraining):
|
||||
| Scene | Karman Joint Formula | PPO Baseline |
|
||||
|-------|:-------------------:|:------------:|
|
||||
| vortex_lamb | **0.949** | 0.942 |
|
||||
| vortex_taylor | **0.905** | 0.916 |
|
||||
```
|
||||
SR_analysis/
|
||||
PIPELINE.md # 总览文档 (入口)
|
||||
README.md # 本文件
|
||||
sindy_sr_knowledge.md # 知识库 (bugs, 事实, 结果)
|
||||
sindy_sr_notes.md # 任务清单
|
||||
scene_registry.json # 所有场景的规范结果索引
|
||||
configs.py # 场景注册表
|
||||
core/ # 共享工具库
|
||||
features.py # 特征构建 (无量纲化+phase-state)
|
||||
fitting.py # STLSQ拟合+特征矩阵
|
||||
cfd.py # LegacyCelerisLab接口
|
||||
g_operator.py # G-mirror变换
|
||||
data/ # 运行时生成的.npz数据
|
||||
results/
|
||||
formulas/ # 规范公式JSON
|
||||
validations/ # CFD闭环验证结果
|
||||
archive/ # 归档的中间文件
|
||||
stage_1_infer.py # Stage 1: 统一PPO推理入口
|
||||
STAGE_1_INFER.md
|
||||
stage_2_fit.py # Stage 2: 统一PySR拟合入口
|
||||
STAGE_2_FIT.md
|
||||
stage_3_validate.py # Stage 3: 统一CFD闭环验证入口
|
||||
STAGE_3_VALIDATE.md
|
||||
stage_4_analyze.py # Stage 4: 统一分析/画图入口
|
||||
STAGE_4_ANALYZE.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pipeline Overview
|
||||
|
||||
```
|
||||
controlled.npz (PPO rollout)
|
||||
|
|
||||
v
|
||||
compute_features() --> dimensionless physics features (ILLUSION_PHASE_KEYS, etc.)
|
||||
|
|
||||
v
|
||||
PySR symbolic regression --> sparse interpretable formulas
|
||||
|
|
||||
v
|
||||
CFD closed-loop validation --> final similarity score
|
||||
```
|
||||
|
||||
### Key Design Decisions
|
||||
## Key Design Decisions
|
||||
|
||||
1. **Feature levels**: Static (8-dim) -> Phase-state (6-dim) -> Illusion-phase (10-dim)
|
||||
2. **Output target**: Non-dimensional alpha, not physical omega
|
||||
3. **v23 structure**: Front no-bias, rear shared-head (Bottom = -Top(Gx))
|
||||
4. **Final judge**: CFD closed-loop similarity, not one-step R2
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
SR_analysis/
|
||||
configs.py # Scene metadata (Karman, Illusion, Vortex)
|
||||
configs/legacy/ # Legacy CFD configs (config_cuda.json, config_flowfield.json)
|
||||
utils/
|
||||
__init__.py # Exports (no pycuda dependency)
|
||||
feature_builder.py # Dimensionless features, G-operator, phase-state features
|
||||
sindy_fitter.py # STLSQ fitting + feature matrices
|
||||
cfd_interface.py # LegacyCelerisLab wrapper (requires pycuda_3_10)
|
||||
g_operator.py # Equivariance diagnostics
|
||||
data/ # Inference output data (controlled.npz, target.npz)
|
||||
karman/ karman_re50..400/
|
||||
illusion/ illusion_0.75L,1L,1.5L/
|
||||
vortex/ vortex_lamb,taylor/
|
||||
scripts/
|
||||
infer_karman.py # PPO inference -> controlled.npz
|
||||
infer_illusion.py # PPO inference -> controlled.npz
|
||||
infer_vortex.py # PPO inference -> controlled.npz
|
||||
gen_illusion_target.py # Target data generation for generalization scenes
|
||||
visualize_ppo_illusion.py# PPO visualization with vorticity
|
||||
sindy/
|
||||
run_pysr.py # PySR symbolic regression (niter=40)
|
||||
run_pysr_deep.py # Karman deep PySR (niter=120, Re independent + joint)
|
||||
run_pysr_deep_illusion.py# Illusion deep+joint PySR (niter=120)
|
||||
validate/
|
||||
run_closed_loop.py # Karman closed-loop validator
|
||||
run_closed_loop_illusion.py # Illusion closed-loop validator
|
||||
run_closed_loop_vortex.py # Vortex closed-loop validator
|
||||
run_closed_loop_re400_si.py # Karman re400 short-SI validator
|
||||
predict_pysr.py # PySR formula sympy.lambdify wrapper
|
||||
eval_rollout.py # Offline multi-step rollout evaluation
|
||||
launch_pysr_validation.py # Batch CFD validation launcher
|
||||
batch_illusion_generalization.sh# Batch generalization CFD validation
|
||||
results/ # 136 JSON files — canonical + intermediate
|
||||
results/README.md # Result file reference table
|
||||
results/archive/ # Archived intermediate search attempts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### PySR Symbolic Regression (conda: sr_env)
|
||||
|
||||
```bash
|
||||
# Illusion
|
||||
conda run -n sr_env python src/SR_analysis/sindy/run_pysr_deep_illusion.py --individual
|
||||
|
||||
# Karman deep (cross-Re independent + joint)
|
||||
conda run -n sr_env python src/SR_analysis/sindy/run_pysr_deep.py --both
|
||||
```
|
||||
|
||||
### CFD Closed-Loop Validation (conda: pycuda_3_10, GPU 1 or 2)
|
||||
|
||||
```bash
|
||||
# Illusion PySR formula
|
||||
conda run -n pycuda_3_10 python src/SR_analysis/validate/run_closed_loop_illusion.py \
|
||||
--scene illusion_1L --device 2 --steps 320 --mode pysr \
|
||||
--pysr-front validate/results/pysr_illusion_1L_front.json \
|
||||
--pysr-top validate/results/pysr_illusion_1L_top.json
|
||||
|
||||
# Karman joint formula
|
||||
conda run -n pycuda_3_10 python src/SR_analysis/validate/run_closed_loop.py \
|
||||
--scene karman_re100 --device 2 --steps 200 --mode pysr \
|
||||
--pysr-front validate/results/karman_joint_deep_front.json \
|
||||
--pysr-top validate/results/karman_joint_deep_top.json
|
||||
|
||||
# Vortex (generalization test)
|
||||
conda run -n pycuda_3_10 python src/SR_analysis/validate/run_closed_loop_vortex.py \
|
||||
--scene vortex_lamb --device 2 --steps 150 --mode pysr \
|
||||
--pysr-front validate/results/karman_joint_deep_front.json \
|
||||
--pysr-top validate/results/karman_joint_deep_top.json
|
||||
```
|
||||
|
||||
### PPO Inference (generate controlled.npz)
|
||||
|
||||
```bash
|
||||
conda run -n pycuda_3_10 python src/SR_analysis/scripts/infer_karman.py --re 100 --device 2
|
||||
conda run -n pycuda_3_10 python src/SR_analysis/scripts/infer_illusion.py --diameter 1.0 --device 2
|
||||
conda run -n pycuda_3_10 python src/SR_analysis/scripts/infer_vortex.py --type lamb --device 2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Critical Reminders
|
||||
|
||||
- **actions.npz are normalized [-1,1]**, not physical omega. Convert: `(action * scale + bias) * u0`
|
||||
- **PySR needs `sensors_raw`/`forces_raw`** passed to `compute_features()` or derivative features are zero
|
||||
- **Output target must be alpha** (non-dim): `Y = actions_phys / u0`
|
||||
- **One-step R2 high != closed-loop good** -- always validate in CFD
|
||||
- **Controls must propagate**: steps >= NX/u0/SI (S=400->320, S=600->214, S=800->160)
|
||||
- **FIFO bias != DRL action bias** for Illusion: FIFO=[0,-U0,U0], decode=[0,-2,2]*U0
|
||||
- **Joint formula must be manually reviewed** for spurious terms (e.g. `daB_dt` is constant=0 at deployment)
|
||||
|
||||
---
|
||||
|
||||
## Key Documentation
|
||||
|
||||
| File | Content |
|
||||
|------|---------|
|
||||
| `src/SR_analysis/sindy_sr_knowledge.md` | Background knowledge, bug history, known pitfalls (for coder reference) |
|
||||
| `src/SR_analysis/sindy_sr_notes.md` | Task list, phase breakdown, current status |
|
||||
| `docs/SR_analysis_report.md` | **Single consolidated report** — all formulas, results, methodology, structural analysis |
|
||||
| `docs/illusion_joint_formula_analysis.md` | Illusion joint formula deep dive — physical interpretation, generalization curve |
|
||||
| `PIPELINE.md` | **Primary entry** — pipeline overview, environment, conventions |
|
||||
| `sindy_sr_knowledge.md` | Bug history, confirmed facts, known limitations |
|
||||
| `sindy_sr_notes.md` | Task list, current status |
|
||||
| `docs/SR_analysis_report.md` | Full report (465+ lines) |
|
||||
| `docs/illusion_joint_formula_analysis.md` | Illusion joint formula deep dive |
|
||||
|
||||
## Core Files (≤20)
|
||||
|
||||
`stage_1_infer.py`, `stage_2_fit.py`, `stage_3_validate.py`, `stage_4_analyze.py`, `configs.py`, `scene_registry.json`, `core/features.py`, `core/fitting.py`, `core/cfd.py`, `core/g_operator.py` + 8 docs.
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Stage 1: PPO Inference
|
||||
|
||||
Generates `controlled.npz` data by running trained PPO models in LegacyCelerisLab CFD.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
conda run -n pycuda_3_10 python stage_1_infer.py --scene karman_re100 --device 2
|
||||
conda run -n pycuda_3_10 python stage_1_infer.py --group karman_trained --device 2
|
||||
conda run -n pycuda_3_10 python stage_1_infer.py --scene illusion_0.6L --target-only --device 2
|
||||
```
|
||||
|
||||
## Scene Groups
|
||||
|
||||
karman_trained (re50-400), illusion_trained (0.75L/1L/1.5L), illusion_generalization (0.5L-2L), vortex_all.
|
||||
|
||||
## Output per Scene
|
||||
|
||||
`data/{scene_id}/{scene_name}/`: target.npz, controlled.npz, config.json, norm.json, result.json, target_harmonics.json (Illusion only).
|
||||
|
||||
actions in controlled.npz are normalized [-1,+1]. Physical omega = (action*scale+bias)*U0.
|
||||
|
||||
## Per-Scene Notes
|
||||
|
||||
- **Karman**: 7 objects, obs_slice=(2,14), action_bias=[0,-4,4], s_dim=12
|
||||
- **Illusion**: 6 objects, obs_slice=(0,12), action_bias=[0,-2,2], s_dim=14, FIFO bias=[0,-U0,U0] differs from DRL bias
|
||||
- **Vortex**: 6 objects, MAX_STEPS=150, action_scale=4, vortex added after DDF checkpoint
|
||||
|
||||
## Expected Similarities
|
||||
|
||||
Karman re100 ~0.90, Illusion 1L ~0.97, Illusion 0.75L ~0.98, Illusion 1.5L ~0.95
|
||||
@@ -0,0 +1,45 @@
|
||||
# Stage 2: PySR Symbolic Regression
|
||||
|
||||
Fits interpretable formulas (obs → act) from controlled.npz data using PySR.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Per-scene fitting
|
||||
conda run -n sr_env python stage_2_fit.py --scene karman_re100 --mode per-scene
|
||||
|
||||
# Joint cross-scene
|
||||
conda run -n sr_env python stage_2_fit.py --scenes karman_re50,karman_re100,karman_re200,karman_re400 --mode joint
|
||||
|
||||
# Deep search
|
||||
conda run -n sr_env python stage_2_fit.py --scenes illusion_0.75L,illusion_1L --mode joint --deep
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
`results/formulas/{label}_{front,top}.json`: best_sympy formula, feature_keys, R2 score.
|
||||
|
||||
Fitting target is non-dimensional **alpha = omega/U0** (not physical omega).
|
||||
|
||||
## Feature Sets
|
||||
|
||||
- **PHASE_STATE_KEYS** (6): u_a, du_a_dt, Cl_tot, dCl_tot_dt, Cd_tot, Cd_rear — Karman per-Re
|
||||
- **ILLUSION_PHASE_KEYS** (10): above + Cd_err, Cl_err, dCd_err_dt, dCl_err_dt — Illusion
|
||||
- **PHYS_DADT + mu** (17): physics + daF/dt + mu modulation — Karman joint
|
||||
|
||||
## Per-Scene vs Joint
|
||||
|
||||
- **per-scene**: Fit one formula per scene. Use for individual Re/diameter analysis.
|
||||
- **joint**: Concatenate multiple scenes' data, fit single formula. Use for cross-scene generalization.
|
||||
|
||||
## Formula Review Checklist
|
||||
|
||||
After fitting, check:
|
||||
1. **No spurious terms**: `daB_dt` = 0 at deployment (rear constant), remove if present
|
||||
2. **Front no-bias**: α_F ≈ 0 when all features ≈ 0
|
||||
3. **Rear shared-head**: α_B = -α_T when flow is symmetric (G-mirror applied)
|
||||
4. **One-step R2 ≠ closed-loop**: Always validate in Stage 3
|
||||
|
||||
## Environments
|
||||
|
||||
`conda run -n sr_env` (PySR installed, separate from pycuda to avoid CUDA conflicts).
|
||||
@@ -0,0 +1,52 @@
|
||||
# Stage 3: CFD Closed-Loop Validation
|
||||
|
||||
Validates PySR formulas or PPO baselines in closed-loop CFD. Final judge is DTW similarity (not one-step R2).
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# PySR formula validation
|
||||
conda run -n pycuda_3_10 python stage_3_validate.py \
|
||||
--scene karman_re100 --device 2 --mode pysr \
|
||||
--formula-front results/formulas/karman_joint_front.json \
|
||||
--formula-top results/formulas/karman_joint_top.json
|
||||
|
||||
# PPO baseline
|
||||
conda run -n pycuda_3_10 python stage_3_validate.py --scene illusion_1L --device 2 --mode ppo
|
||||
|
||||
# Batch generalization
|
||||
conda run -n pycuda_3_10 python stage_3_validate.py \
|
||||
--group illusion_generalization --device 2 --mode pysr \
|
||||
--formula-front results/formulas/illusion_joint_front.json \
|
||||
--formula-top results/formulas/illusion_joint_top.json
|
||||
```
|
||||
|
||||
## Modes
|
||||
|
||||
- **pysr**: Deploy PySR formula in closed-loop CFD (v23: front no-bias, rear shared-head)
|
||||
- **ppo**: Run trained PPO model as baseline
|
||||
- **uncontrolled**: Zero-action baseline
|
||||
|
||||
## Steps
|
||||
|
||||
Auto-calculated from sample interval: SI=400→320, SI=600→214, SI=800→160.
|
||||
|
||||
## Output
|
||||
|
||||
`results/validations/{scene_name}.json`: similarity score, mode, n_steps.
|
||||
|
||||
## v23 Structure
|
||||
|
||||
- Front: α_F = f_front(x), no bias — should be ~0 when features ~0
|
||||
- Top: α_T = f_rear(x), with bias
|
||||
- Bottom: α_B = -f_rear(G[x]) — shared-head via G-mirror
|
||||
|
||||
G-mirror: [aF,aT,aB]→[-aF,-aB,-aT], sensors swap top↔bottom with v sign flip.
|
||||
|
||||
## Similarity Interpretation
|
||||
|
||||
- > 0.90: Excellent (cloak/illusion effective)
|
||||
- 0.70-0.90: Partial control
|
||||
- < 0.50: Poor
|
||||
|
||||
Tail similarity isolates the far-wake portion.
|
||||
@@ -0,0 +1,38 @@
|
||||
# Stage 4: Analysis & Visualization
|
||||
|
||||
Analyzes PPO policies and SR formulas. Generates FFT spectra, action timeseries, and degradation curves.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# PPO action visualization (timeseries + FFT)
|
||||
conda run -n pycuda_3_10 python stage_4_analyze.py --scene illusion_1L --mode ppo-viz
|
||||
|
||||
# Cross-diameter degradation analysis
|
||||
conda run -n pycuda_3_10 python stage_4_analyze.py \
|
||||
--scenes illusion_0.75L,illusion_1L,illusion_1.5L --mode degradation
|
||||
|
||||
# Formula comparison (coming soon)
|
||||
conda run -n pycuda_3_10 python stage_4_analyze.py --scene illusion_1L --mode formula-compare
|
||||
```
|
||||
|
||||
## Modes
|
||||
|
||||
- **ppo-viz**: Action timeseries plot + FFT spectrum for each cylinder
|
||||
- **degradation**: Cross-scene comparison (alpha std, Cd_tot, action range) — finds transition points where control regime changes
|
||||
- **formula-compare**: (placeholder) Compare PySR formula predictions vs PPO actions
|
||||
|
||||
## Output
|
||||
|
||||
Figures written to `data/figures/`:
|
||||
- `ppo_viz_{scene}.png` — timeseries + FFT
|
||||
- `degradation_metrics.png` — cross-diameter comparison panels
|
||||
|
||||
## Regime Detection
|
||||
|
||||
The degradation mode detects control regime transitions by:
|
||||
1. Action amplitude jump (alpha std > 4x)
|
||||
2. Frequency shift (FFT dominant frequency > 5x)
|
||||
3. Autocorrelation pattern change (lag-2 ≈ -0.9 = high-frequency switching)
|
||||
|
||||
Known transition: Illusion 1.5L shifts from phase-lead compensation to high-frequency periodic modulation.
|
||||
@@ -0,0 +1,403 @@
|
||||
"""CFD interface for LegacyCelerisLab (pycuda_3_10 env).
|
||||
|
||||
All functions use the LegacyCelerisLab (old) CFD API via:
|
||||
from LegacyCelerisLab import FlowField
|
||||
|
||||
Must be run inside: conda run -n pycuda_3_10
|
||||
|
||||
NOTE: This module should be imported directly, not through SR_analysis.utils
|
||||
because it requires pycuda. Other utils (sindy_fitter, feature_builder, g_operator)
|
||||
do NOT require pycuda and can be imported from the __init__.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from collections import deque
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
import numpy as np
|
||||
|
||||
# -- Import legacy CFD -------------------------------------------------------
|
||||
# LegacyCelerisLab lives at the repo root; SR_analysis is at repo_root/src/SR_analysis.
|
||||
_REPO = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
||||
if _REPO not in sys.path:
|
||||
sys.path.insert(0, _REPO)
|
||||
_SRC = os.path.join(_REPO, "src")
|
||||
if _SRC not in sys.path:
|
||||
sys.path.insert(0, _SRC)
|
||||
|
||||
from LegacyCelerisLab import FlowField # noqa: E402
|
||||
from LegacyCelerisLab import utils as legacy_utils # noqa: E402
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Action-smoothing constant (legacy run() internal)
|
||||
# ---------------------------------------------------------------------------
|
||||
ACTION_SMOOTH_WEIGHT = 0.1 # used by FlowField.run() internally
|
||||
|
||||
|
||||
def nu_from_re(re_code: float, u0: float = 0.01, d_ref: float = 40.0) -> float:
|
||||
"""Return kinematic viscosity for a given code Reynolds number.
|
||||
|
||||
``re_code`` uses reference length *2*D* = 40.0 (matching model file naming).
|
||||
"""
|
||||
return u0 * d_ref / re_code
|
||||
|
||||
|
||||
def load_legacy_configs(config_dir: str) -> Tuple[Any, Any]:
|
||||
"""Load and return legacy (cuda_config, field_config) from *config_dir*."""
|
||||
cuda_cfg = legacy_utils.load_cuda_config(
|
||||
os.path.join(config_dir, "config_cuda.json")
|
||||
)
|
||||
field_cfg = legacy_utils.load_flow_field_config(
|
||||
os.path.join(config_dir, "config_flowfield.json")
|
||||
)
|
||||
return cuda_cfg, field_cfg
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Environment helpers -- Karman cloak (disturbance cylinder + pinball)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def build_karman_cloak_env(
|
||||
flow_field: FlowField,
|
||||
*,
|
||||
u0: float,
|
||||
l0: float,
|
||||
sample_interval: int,
|
||||
fifo_len: int,
|
||||
data_type: type,
|
||||
) -> Tuple[np.ndarray, dict]:
|
||||
"""Phase 0-1: add dist-cylinder & 3 sensors, stabilize, record target.
|
||||
|
||||
Steps (mirrors env_karman_cloak_standard.__init__):
|
||||
1. add dist_cylinder (id=0)
|
||||
2. add 3 sensors (id=1,2,3)
|
||||
3. stabilize run(4*NX/U0, zero-action[4])
|
||||
4. record FIFO_LEN x run(SAMPLE_INTERVAL, zero[4]), collect obs[2:8]
|
||||
|
||||
Returns
|
||||
-------
|
||||
target_states : ndarray (FIFO_LEN, 6) -- sensor0/1/2 ux,uy
|
||||
info : dict with n_objects, NX, NY
|
||||
"""
|
||||
# dist cylinder
|
||||
center = (10.0 * l0, (flow_field.FIELD_SHAPE[1] - 1) / 2, 0.0)
|
||||
flow_field.add_cylinder(center, l0)
|
||||
|
||||
# sensors
|
||||
for y_off in [2.0, 0.0, -2.0]:
|
||||
sc = (40.0 * l0, (flow_field.FIELD_SHAPE[1] - 1) / 2 + y_off * l0, 0.0)
|
||||
flow_field.add_sensor(sc, l0 / 4.0)
|
||||
|
||||
n_obj = flow_field.obs.size // 2
|
||||
|
||||
# stabilize
|
||||
stabilize_steps = int(4 * flow_field.FIELD_SHAPE[0] / u0)
|
||||
print(f" stabilising ({stabilize_steps} steps)...")
|
||||
flow_field.run(stabilize_steps, np.zeros(n_obj, dtype=data_type))
|
||||
|
||||
# record target (only sensor signals = obs[2:8])
|
||||
target_states = np.empty((0, 6), dtype=data_type)
|
||||
for _ in range(fifo_len):
|
||||
flow_field.run(sample_interval, np.zeros(n_obj, dtype=data_type))
|
||||
new_state = flow_field.obs.copy()[2:8]
|
||||
target_states = np.vstack((target_states, new_state))
|
||||
|
||||
print(f" target recorded: {target_states.shape}")
|
||||
return target_states, {"n_objects": n_obj, "NX": flow_field.FIELD_SHAPE[0],
|
||||
"NY": flow_field.FIELD_SHAPE[1]}
|
||||
|
||||
|
||||
def add_pinball(
|
||||
flow_field: FlowField,
|
||||
*,
|
||||
l0: float,
|
||||
u0: float,
|
||||
sample_interval: int,
|
||||
fifo_len: int,
|
||||
data_type: type,
|
||||
action_bias: Optional[Tuple[float, float, float]] = None,
|
||||
pinball_front_x: float = 30.0,
|
||||
pinball_rear_x: float = 31.3,
|
||||
obs_slice_start: int = 2,
|
||||
obs_slice_end: int = 14,
|
||||
n_objects_total: Optional[int] = None,
|
||||
) -> dict:
|
||||
"""Add pinball cylinders, stabilize, compute norm, bias rollout.
|
||||
|
||||
Steps:
|
||||
1. add front, bottom, top cylinders
|
||||
2. stabilize run(4*NX/U0, zero-action)
|
||||
3. get_ddf() + save_ddf() (checkpoint)
|
||||
4. FIFO_LEN x run(SAMPLE_INTERVAL, zero) -> compute norm
|
||||
5. apply_ddf() (restore pre-bias state)
|
||||
6. FIFO_LEN x run(SAMPLE_INTERVAL, bias-action) -> save_states
|
||||
7. apply_ddf()
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pinball_front_x, pinball_rear_x : pinball geometry (L0 units).
|
||||
Default 30.0/31.3 for Karman; 19.0/20.3 for Illusion.
|
||||
obs_slice_start, obs_slice_end : slice of obs for norm.
|
||||
Default [2:14] for Karman (7 objects); [0:12] for Illusion (6 objects).
|
||||
n_objects_total : if provided, used for bias array length.
|
||||
Default: inferred from flow_field after adding cylinders.
|
||||
|
||||
Returns dict with norm values.
|
||||
"""
|
||||
if action_bias is None:
|
||||
action_bias = (0.0, -4.0, 4.0)
|
||||
|
||||
u0_float = float(u0)
|
||||
|
||||
# add 3 pinball cylinders
|
||||
ny = flow_field.FIELD_SHAPE[1]
|
||||
centers = [
|
||||
(pinball_front_x * l0, (ny - 1) / 2, 0.0),
|
||||
(pinball_rear_x * l0, (ny - 1) / 2 + 0.75 * l0, 0.0),
|
||||
(pinball_rear_x * l0, (ny - 1) / 2 - 0.75 * l0, 0.0),
|
||||
]
|
||||
for c in centers:
|
||||
flow_field.add_cylinder(c, l0 / 2.0)
|
||||
|
||||
n_obj = flow_field.obs.size // 2 if n_objects_total is None else n_objects_total
|
||||
print(f" bodies after pinball: {n_obj}")
|
||||
|
||||
# stabilize
|
||||
stabilize_steps = int(4 * flow_field.FIELD_SHAPE[0] / u0_float)
|
||||
print(f" stabilising pinball ({stabilize_steps} steps)...")
|
||||
flow_field.run(stabilize_steps, np.zeros(n_obj, dtype=data_type))
|
||||
|
||||
# checkpoint DDF
|
||||
flow_field.get_ddf()
|
||||
flow_field.save_ddf()
|
||||
|
||||
# --- norm phase (zero-action) ---
|
||||
fifo = deque(maxlen=fifo_len)
|
||||
for _ in range(fifo_len):
|
||||
flow_field.run(sample_interval, np.zeros(n_obj, dtype=data_type))
|
||||
fifo.append(flow_field.obs.copy()[obs_slice_start:obs_slice_end])
|
||||
|
||||
temp_states = np.array(fifo, dtype=data_type)
|
||||
# forces are at indices [6:12] relative to the slice end
|
||||
force_start = obs_slice_end - obs_slice_start - 6
|
||||
force_end = force_start + 6
|
||||
force_norm_fact = 6.0 * float(np.max(np.abs(temp_states[:, force_start:force_end])))
|
||||
sens_deviation = np.mean(temp_states[:, 0:6], axis=0).astype(data_type)
|
||||
sens_norm_fact = np.zeros(6, dtype=data_type)
|
||||
for i in range(6):
|
||||
sens_norm_fact[i] = 5.0 * float(np.max(np.abs(temp_states[:, i] - sens_deviation[i])))
|
||||
|
||||
print(f" norm: force_norm_fact={force_norm_fact:.6f}")
|
||||
print(f" norm: sens_deviation={sens_deviation}")
|
||||
print(f" norm: sens_norm_fact={sens_norm_fact}")
|
||||
|
||||
# --- bias-action rollout ---
|
||||
flow_field.apply_ddf()
|
||||
bias = np.zeros(n_obj, dtype=data_type)
|
||||
bias[n_obj - 3] = float(action_bias[0] * u0_float)
|
||||
bias[n_obj - 2] = float(action_bias[1] * u0_float)
|
||||
bias[n_obj - 1] = float(action_bias[2] * u0_float)
|
||||
print(f" bias action: {bias}")
|
||||
|
||||
fifo.clear()
|
||||
for _ in range(fifo_len):
|
||||
flow_field.run(sample_interval, bias)
|
||||
fifo.append(flow_field.obs.copy()[obs_slice_start:obs_slice_end])
|
||||
|
||||
save_states = np.array(list(fifo), dtype=data_type)
|
||||
# CRITICAL: save DDF again AFTER bias FIFO, so restore_ddf() goes
|
||||
# to the post-bias state (consistent with saved FIFO).
|
||||
# Without this, reset() restores to a bare stabilized state with
|
||||
# no bias history, invalidating the FIFO.
|
||||
flow_field.get_ddf()
|
||||
flow_field.save_ddf()
|
||||
flow_field.apply_ddf()
|
||||
|
||||
return {
|
||||
"force_norm_fact": force_norm_fact,
|
||||
"sens_deviation": sens_deviation.tolist(),
|
||||
"sens_norm_fact": sens_norm_fact.tolist(),
|
||||
"action_bias": list(action_bias),
|
||||
"save_states": save_states,
|
||||
}
|
||||
|
||||
|
||||
def build_observation(
|
||||
obs_slice: np.ndarray,
|
||||
norm: dict,
|
||||
) -> np.ndarray:
|
||||
"""Assemble normalised DRL observation (12-dim) from a single obs slice.
|
||||
|
||||
``obs_slice`` is 12-element: sensor[0:6] + force[6:12].
|
||||
|
||||
Returns clipped 12-dim array in [-1, 1].
|
||||
"""
|
||||
forces = obs_slice[6:12] / norm["force_norm_fact"]
|
||||
sens = (obs_slice[0:6] - norm["sens_deviation"]) / norm["sens_norm_fact"]
|
||||
obs = np.clip(np.hstack([forces, sens]), -1.0, 1.0).astype(np.float32)
|
||||
return obs
|
||||
|
||||
|
||||
def action_to_physical(
|
||||
action_norm: np.ndarray,
|
||||
*,
|
||||
scale: float = 8.0,
|
||||
bias: Tuple[float, float, float] = (0.0, -4.0, 4.0),
|
||||
u0: float = 0.01,
|
||||
) -> np.ndarray:
|
||||
"""Convert normalized action [-1,1] to physical omega (lattice units).
|
||||
|
||||
physical_omega[i] = (action_norm[i] * scale + bias[i]) * u0
|
||||
"""
|
||||
action_norm = np.asarray(action_norm, dtype=np.float64).reshape(-1, 3)
|
||||
bias_arr = np.array(bias, dtype=np.float64)
|
||||
return (action_norm * scale + bias_arr) * u0
|
||||
|
||||
|
||||
def scale_action(
|
||||
action_norm: np.ndarray,
|
||||
*,
|
||||
scale: float = 8.0,
|
||||
bias: Tuple[float, float, float] = (0.0, -4.0, 4.0),
|
||||
u0: float = 0.01,
|
||||
n_total_bodies: int = 7,
|
||||
) -> np.ndarray:
|
||||
"""Convert normalised action ([-1,1]^3) to legacy CFD action array.
|
||||
|
||||
Returns array of length *n_total_bodies* with cylinders' omegas at the
|
||||
last 3 slots.
|
||||
"""
|
||||
a = np.zeros(n_total_bodies, dtype=np.float32)
|
||||
omega = (np.array(action_norm, dtype=np.float32) * scale + np.array(bias, dtype=np.float32)) * u0
|
||||
a[n_total_bodies - 3:] = omega
|
||||
return a
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Vorticity & field export
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def vorticity_from_ddf(flow_field: FlowField, u0: float) -> np.ndarray:
|
||||
"""Compute z-vorticity from current DDF on host."""
|
||||
flow_field.get_ddf()
|
||||
ddf = flow_field.ddf.copy().reshape((9, flow_field.FIELD_SHAPE[1],
|
||||
flow_field.FIELD_SHAPE[0])).transpose(2, 1, 0)
|
||||
ux = (ddf[:, :, 1] + ddf[:, :, 5] + ddf[:, :, 8]
|
||||
- ddf[:, :, 3] - ddf[:, :, 6] - ddf[:, :, 7]) / u0
|
||||
uy = (ddf[:, :, 2] + ddf[:, :, 5] + ddf[:, :, 6]
|
||||
- ddf[:, :, 4] - ddf[:, :, 7] - ddf[:, :, 8]) / u0
|
||||
omega = np.gradient(uy, axis=0) - np.gradient(ux, axis=1)
|
||||
return omega.astype(np.float64)
|
||||
|
||||
|
||||
def save_vorticity_png(path: str, omega: np.ndarray, title: str = ""):
|
||||
"""Save vorticity field as a PNG with symmetric colour bar."""
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
abs_o = np.abs(omega[np.isfinite(omega)])
|
||||
vmax = float(np.percentile(abs_o, 99.5)) if abs_o.size > 0 else 1.0
|
||||
if vmax <= 0:
|
||||
vmax = 1.0
|
||||
|
||||
ny, nx = omega.shape
|
||||
fig, ax = plt.subplots(figsize=(min(18, max(8, nx / 60)), min(10, max(3, ny / 40))))
|
||||
im = ax.imshow(omega, origin="lower", aspect="equal", cmap="RdBu_r",
|
||||
vmin=-vmax, vmax=vmax, extent=(0, nx - 1, 0, ny - 1))
|
||||
ax.set_xlabel("x (lattice)")
|
||||
ax.set_ylabel("y (lattice)")
|
||||
if title:
|
||||
ax.set_title(title)
|
||||
fig.colorbar(im, ax=ax, fraction=0.046, pad=0.04, label=r"$\omega_z$")
|
||||
fig.tight_layout()
|
||||
fig.savefig(path, dpi=150, bbox_inches="tight")
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# DTW similarity
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def calc_lag(target: np.ndarray, state: np.ndarray) -> int:
|
||||
"""Find lag that maximises cross-correlation between two 1-D signals."""
|
||||
t = target - np.mean(target)
|
||||
s = state - np.mean(state)
|
||||
corr = np.correlate(t, s, mode="full")
|
||||
lags = np.arange(-len(target) + 1, len(target))
|
||||
return int(lags[np.argmax(corr)])
|
||||
|
||||
|
||||
def calc_dtw_sim(target: np.ndarray, state: np.ndarray) -> float:
|
||||
"""DTW-based similarity: 1 - (DTW distance / len(target))."""
|
||||
n, m = len(target), len(state)
|
||||
dtw = np.full((n + 1, m + 1), np.inf)
|
||||
dtw[0, 0] = 0.0
|
||||
for i in range(1, n + 1):
|
||||
for j in range(1, m + 1):
|
||||
cost = abs(float(target[i - 1]) - float(state[j - 1]))
|
||||
dtw[i, j] = cost + min(dtw[i - 1, j], dtw[i, j - 1], dtw[i - 1, j - 1])
|
||||
return float(1.0 - dtw[n, m] / n)
|
||||
|
||||
|
||||
def compute_similarity(
|
||||
target_states: np.ndarray,
|
||||
state_series: np.ndarray,
|
||||
conv_len: int,
|
||||
) -> float:
|
||||
"""Compute lag-compensated DTW similarity over *conv_len* window."""
|
||||
ref = target_states[conv_len:2 * conv_len, 1]
|
||||
cur = state_series[-conv_len:, 1]
|
||||
lag = calc_lag(ref, cur)
|
||||
|
||||
sim_sum = 0.0
|
||||
for i in range(6):
|
||||
target_seq = np.roll(target_states[:, i], -lag)[conv_len:2 * conv_len]
|
||||
state_seq = state_series[-conv_len:, i]
|
||||
sim_sum += calc_dtw_sim(target_seq, state_seq) / 6.0
|
||||
return float(sim_sum)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Dummy env for loading SB3 models
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def create_dummy_env(s_dim: int = 12, a_dim: int = 3):
|
||||
"""Return a gym.Env with correct observation/action spaces for model loading."""
|
||||
import gymnasium as gym
|
||||
from gymnasium import spaces
|
||||
|
||||
class DummyEnv(gym.Env):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.observation_space = spaces.Box(low=-1, high=1, shape=(s_dim,), dtype=np.float32)
|
||||
self.action_space = spaces.Box(low=-1, high=1, shape=(a_dim,), dtype=np.float32)
|
||||
|
||||
def reset(self, seed=None):
|
||||
return np.zeros(s_dim, dtype=np.float32), {}
|
||||
|
||||
def step(self, action):
|
||||
return np.zeros(s_dim, dtype=np.float32), 0.0, False, False, {}
|
||||
|
||||
def render(self):
|
||||
pass
|
||||
|
||||
return DummyEnv()
|
||||
|
||||
|
||||
def load_ppo_model(model_path: str, device: str = "cuda:0", s_dim: int = 12, a_dim: int = 3):
|
||||
"""Load a PPO model with Sin activation."""
|
||||
import torch
|
||||
from torch.nn import Module
|
||||
from stable_baselines3 import PPO
|
||||
|
||||
class Sin(Module):
|
||||
def forward(self, x):
|
||||
return torch.sin(x)
|
||||
|
||||
dummy_env = create_dummy_env(s_dim, a_dim)
|
||||
model = PPO.load(model_path, env=dummy_env, device=device)
|
||||
return model
|
||||
@@ -0,0 +1,386 @@
|
||||
"""Unified feature builder for all cloak scenes.
|
||||
|
||||
Produces dimensionless features with consistent G-equivariant structure.
|
||||
All scenes (Karman, steady, vortex, illusion) use this same builder.
|
||||
|
||||
Copy of analysis_cloak/common/feature_builder.py -- kept as canonical source.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
# -- Physical constants ------------------------------------------------------
|
||||
U0 = 0.01 # inlet velocity (lattice units)
|
||||
D_CYL = 20.0 # cylinder diameter (lattice)
|
||||
|
||||
|
||||
# -- Dimensionless conversion ------------------------------------------------
|
||||
|
||||
def compute_dimensionless(
|
||||
sensors: np.ndarray, # (T, 6) raw lattice [s0_ux,s0_uy, s1_ux,s1_uy, s2_ux,s2_uy]
|
||||
forces: np.ndarray, # (T, 6) raw lattice [f0_fx,f0_fy, f1_fx,f1_fy, f2_fx,f2_fy]
|
||||
u0: float = U0,
|
||||
d: float = D_CYL,
|
||||
rho: float = 1.0,
|
||||
) -> Dict[str, np.ndarray]:
|
||||
"""Convert raw lattice CFD data to dimensionless quantities.
|
||||
|
||||
Sensor order: [s0_ux,s0_uy, s1_ux,s1_uy, s2_ux,s2_uy]
|
||||
where s0=top(y=+2L0), s1=mid(y=0), s2=bottom(y=-2L0)
|
||||
Force order: [front_fx,front_fy, bottom_fx,bottom_fy, top_fx,top_fy]
|
||||
|
||||
Returns:
|
||||
u_hat_B, u_hat_C, u_hat_T: nondim streamwise velocity (bottom/centre/top)
|
||||
v_hat_B, v_hat_C, v_hat_T: nondim crosswise velocity
|
||||
Cd_F, Cd_T, Cd_B: drag coefficient per cylinder
|
||||
Cl_F, Cl_T, Cl_B: lift coefficient per cylinder
|
||||
"""
|
||||
s = np.asarray(sensors, dtype=np.float64)
|
||||
f = np.asarray(forces, dtype=np.float64)
|
||||
|
||||
# Sensor positions: s0=top, s1=centre, s2=bottom
|
||||
# Convention: B=bottom=s2, C=centre=s1, T=top=s0
|
||||
return {
|
||||
"u_hat_T": s[:, 0] / u0,
|
||||
"v_hat_T": s[:, 1] / u0,
|
||||
"u_hat_C": s[:, 2] / u0,
|
||||
"v_hat_C": s[:, 3] / u0,
|
||||
"u_hat_B": s[:, 4] / u0,
|
||||
"v_hat_B": s[:, 5] / u0,
|
||||
"Cd_F": 2.0 * f[:, 0] / (rho * u0**2 * d),
|
||||
"Cl_F": 2.0 * f[:, 1] / (rho * u0**2 * d),
|
||||
"Cd_B": 2.0 * f[:, 2] / (rho * u0**2 * d),
|
||||
"Cl_B": 2.0 * f[:, 3] / (rho * u0**2 * d),
|
||||
"Cd_T": 2.0 * f[:, 4] / (rho * u0**2 * d),
|
||||
"Cl_T": 2.0 * f[:, 5] / (rho * u0**2 * d),
|
||||
}
|
||||
|
||||
|
||||
# -- G operator (corrected) --------------------------------------------------
|
||||
|
||||
def apply_G_alpha(alpha: np.ndarray) -> np.ndarray:
|
||||
"""Apply mirror G to action: [aF, aT, aB] -> [-aF, -aB, -aT]."""
|
||||
return np.array([-alpha[0], -alpha[2], -alpha[1]], dtype=alpha.dtype)
|
||||
|
||||
|
||||
def apply_G_x(dim: Dict[str, np.ndarray],
|
||||
a_prev: np.ndarray,
|
||||
a_prev2: np.ndarray) -> Tuple[Dict, np.ndarray, np.ndarray]:
|
||||
"""Apply G to dimensionless state.
|
||||
|
||||
Returns (G_dim, G_a_prev, G_a_prev2) with corrected sign rules.
|
||||
"""
|
||||
G_dim = {
|
||||
"u_hat_B": dim["u_hat_T"], "u_hat_C": dim["u_hat_C"], "u_hat_T": dim["u_hat_B"],
|
||||
"v_hat_B": -dim["v_hat_T"], "v_hat_C": -dim["v_hat_C"], "v_hat_T": -dim["v_hat_B"],
|
||||
"Cd_F": dim["Cd_F"], "Cd_T": dim["Cd_B"], "Cd_B": dim["Cd_T"],
|
||||
"Cl_F": -dim["Cl_F"], "Cl_T": -dim["Cl_B"], "Cl_B": -dim["Cl_T"],
|
||||
}
|
||||
G_a_prev = np.column_stack([-a_prev[:, 0], -a_prev[:, 2], -a_prev[:, 1]])
|
||||
G_a_prev2 = np.column_stack([-a_prev2[:, 0], -a_prev2[:, 2], -a_prev2[:, 1]])
|
||||
return G_dim, G_a_prev, G_a_prev2
|
||||
|
||||
|
||||
# -- Feature key definitions -------------------------------------------------
|
||||
|
||||
# Original feature set (includes sin_ua/cos_ua)
|
||||
CORE_FEAT_KEYS = [
|
||||
"u_m", "u_a", "u_c",
|
||||
"v_a",
|
||||
"Cd_tot", "Cd_rear",
|
||||
"Cl_tot", "Cl_diff",
|
||||
"sin_ua", "cos_ua",
|
||||
"aF_lag1", "aB_lag1", "aT_lag1",
|
||||
"daF", "daB", "daT",
|
||||
]
|
||||
|
||||
# V2 core features: no sin_ua/cos_ua, no mu (for single-scene fitting)
|
||||
CORE_FEAT_KEYS_V2 = [
|
||||
"u_m", "u_a", "u_c",
|
||||
"v_a",
|
||||
"Cd_tot", "Cd_rear",
|
||||
"Cl_tot", "Cl_diff",
|
||||
"aF_lag1", "aB_lag1", "aT_lag1",
|
||||
"daF", "daB", "daT",
|
||||
]
|
||||
|
||||
# Time-explicit features: da/dt_c (for cross-scene coefficient comparison)
|
||||
TIME_FEAT_KEYS = [
|
||||
"daF_dt", "daB_dt", "daT_dt",
|
||||
]
|
||||
|
||||
MU_FEAT_KEYS = ["mu", "mu_u_a", "mu_v_a", "mu_Cd_tot", "mu_Cl_diff"]
|
||||
|
||||
# Illusion target force features (for scenes where we know the target Cd/Cl)
|
||||
ILLUSION_TARGET_KEYS = ["target_Cd", "target_Cl"]
|
||||
ILLUSION_FEAT_KEYS_V2 = CORE_FEAT_KEYS_V2 + ILLUSION_TARGET_KEYS
|
||||
ILLUSION_ALL_FEAT_KEYS_V2 = ILLUSION_FEAT_KEYS_V2 + MU_FEAT_KEYS # with mu for joint
|
||||
|
||||
# Physics-only feature keys: NO action history terms (no aF_lag1, no daF, etc.)
|
||||
# These are the clean inputs for learning d(alpha)/dt as a function of physics state.
|
||||
PHYSICS_FEAT_KEYS = [
|
||||
"u_m", "u_a", "u_c", "v_a",
|
||||
"Cd_tot", "Cd_rear", "Cl_tot", "Cl_diff",
|
||||
]
|
||||
|
||||
# Illusion error-state: physics features + force error (not raw target forces)
|
||||
ILLUSION_ERR_KEYS = PHYSICS_FEAT_KEYS + ["Cd_err", "Cl_err"]
|
||||
|
||||
# Observation lag (1-step delayed) and derivative (time-normalized) features
|
||||
# These add temporal/phasing information to the otherwise static physics features.
|
||||
LAG_FEAT_KEYS = [
|
||||
"u_m_lag1", "u_a_lag1", "u_c_lag1", "v_a_lag1",
|
||||
"Cd_tot_lag1", "Cd_rear_lag1", "Cl_tot_lag1", "Cl_diff_lag1",
|
||||
]
|
||||
DERIV_FEAT_KEYS = [
|
||||
"du_m_dt", "du_a_dt", "du_c_dt", "dv_a_dt",
|
||||
"dCd_tot_dt", "dCd_rear_dt", "dCl_tot_dt", "dCl_diff_dt",
|
||||
]
|
||||
# Action lag (for ablation level 4 — comparing against old approach)
|
||||
ACTION_LAG_KEYS = ["aF_lag1", "aB_lag1", "aT_lag1"]
|
||||
|
||||
# Augmented levels for ablation study:
|
||||
# Level 0 = x_n (PHYSICS_FEAT_KEYS, no memory at all)
|
||||
# Level 1 = x_n + x_{n-1} (current + 1-step lag)
|
||||
# Level 2 = x_n + dx/dt (current + derivative)
|
||||
# Level 3 = x_n + x_{n-1} + dx/dt (full temporal context)
|
||||
# Level 4 = Level 3 + a_{n-1} (add action history for comparison)
|
||||
AUG_LEVEL_1_KEYS = PHYSICS_FEAT_KEYS + LAG_FEAT_KEYS
|
||||
AUG_LEVEL_2_KEYS = PHYSICS_FEAT_KEYS + DERIV_FEAT_KEYS
|
||||
AUG_LEVEL_3_KEYS = PHYSICS_FEAT_KEYS + LAG_FEAT_KEYS + DERIV_FEAT_KEYS
|
||||
AUG_LEVEL_4_KEYS = AUG_LEVEL_3_KEYS + ACTION_LAG_KEYS
|
||||
|
||||
# Illusion equivalents with error-state
|
||||
ILLUSION_LAG_KEYS = [
|
||||
"Cd_err_lag1", "Cl_err_lag1",
|
||||
]
|
||||
ILLUSION_DERIV_KEYS = [
|
||||
"dCd_err_dt", "dCl_err_dt",
|
||||
]
|
||||
ILLUSION_AUG_LEVEL_1_KEYS = ILLUSION_ERR_KEYS + LAG_FEAT_KEYS + ILLUSION_LAG_KEYS
|
||||
ILLUSION_AUG_LEVEL_2_KEYS = ILLUSION_ERR_KEYS + DERIV_FEAT_KEYS + ILLUSION_DERIV_KEYS
|
||||
ILLUSION_AUG_LEVEL_3_KEYS = ILLUSION_AUG_LEVEL_1_KEYS + DERIV_FEAT_KEYS + ILLUSION_DERIV_KEYS
|
||||
ILLUSION_AUG_LEVEL_4_KEYS = ILLUSION_AUG_LEVEL_3_KEYS + ACTION_LAG_KEYS
|
||||
|
||||
# Phase-state features: low-dimensional dynamic state z = [phase_obs, phase_deriv, static_force]
|
||||
# This replaces the full x_n + x_{n-1} with a compact representation.
|
||||
# The idea: u_a + du_a/dt encodes oscillation phase, Cl_tot + dCl_tot/dt encodes lift dynamics,
|
||||
# and Cd_tot/Cd_rear provide static force feedback.
|
||||
PHASE_STATE_KEYS = [
|
||||
"u_a", "du_a_dt", # oscillation phase (cross-stream asymmetry + rate)
|
||||
"Cl_tot", "dCl_tot_dt", # lift dynamics
|
||||
"Cd_tot", "Cd_rear", # static drag feedback
|
||||
]
|
||||
|
||||
# Karman expanded: phase-state + supplementary static quantities
|
||||
# For Karman, 6-dim phase-state may not capture enough information.
|
||||
# Adding u_m (mean streamwise), u_c (center sensor), v_a (cross asymmetry), Cl_diff (lift distribution)
|
||||
KARMAN_EXPANDED_KEYS = PHASE_STATE_KEYS + [
|
||||
"u_m", "u_c", "v_a", "Cl_diff",
|
||||
]
|
||||
|
||||
# Illusion phase-state: error-based + dynamics
|
||||
ILLUSION_PHASE_KEYS = PHASE_STATE_KEYS + [
|
||||
"Cd_err", "Cl_err", "dCd_err_dt", "dCl_err_dt",
|
||||
]
|
||||
|
||||
ALL_FEAT_KEYS = CORE_FEAT_KEYS + MU_FEAT_KEYS
|
||||
# V2 all features (for cross-Re joint fitting with mu)
|
||||
ALL_FEAT_KEYS_V2 = CORE_FEAT_KEYS_V2 + MU_FEAT_KEYS
|
||||
|
||||
|
||||
# -- Feature computation -----------------------------------------------------
|
||||
|
||||
def compute_features(
|
||||
dim: Dict[str, np.ndarray],
|
||||
actions_prev: np.ndarray, # (T, 3) physical omega(t-1) or nondim alpha(t-1)
|
||||
actions_prev2: np.ndarray, # (T, 3) physical omega(t-2)
|
||||
mu: float,
|
||||
alpha_mode: bool = False, # if True, actions_prev are already nondim alpha
|
||||
include_mu: bool = True,
|
||||
include_cos_sin: bool = True, # if True, include sin_ua/cos_ua features
|
||||
dt_c: float = 1.0, # control interval in T0 units (for time normalization)
|
||||
u0: float = U0, # inlet velocity for omega->alpha conversion
|
||||
target_forces: Optional[np.ndarray] = None, # (T, 2) raw lattice target forces [fx,fy]
|
||||
rho: float = 1.0, # fluid density for Cd/Cl conversion
|
||||
sensors_raw: Optional[np.ndarray] = None, # (T, 6) raw lattice sensors, for obs dynamics
|
||||
forces_raw: Optional[np.ndarray] = None, # (T, 6) raw lattice forces, for obs dynamics
|
||||
) -> Dict[str, np.ndarray]:
|
||||
"""Compute unified feature dictionary from dimensionless primitives.
|
||||
|
||||
Args:
|
||||
dim: from compute_dimensionless()
|
||||
actions_prev: lagged actions (physical omega or nondim alpha)
|
||||
actions_prev2: twice-lagged actions
|
||||
mu: 1/Re_D
|
||||
alpha_mode: if True, actions are already nondim; else convert
|
||||
include_mu: include mu modulation terms
|
||||
include_cos_sin: include sin_ua/cos_ua phase encoding
|
||||
dt_c: control interval (in T0 = D/U0 units), for time-normalized deltas
|
||||
u0: inlet velocity (lattice), used only when alpha_mode=False
|
||||
|
||||
Returns dict with all features as (T,) or (T,3) arrays.
|
||||
"""
|
||||
T = actions_prev.shape[0]
|
||||
u_B, u_C, u_T = dim["u_hat_B"], dim["u_hat_C"], dim["u_hat_T"]
|
||||
v_B, v_C, v_T = dim["v_hat_B"], dim["v_hat_C"], dim["v_hat_T"]
|
||||
Cd_F, Cd_T, Cd_B = dim["Cd_F"], dim["Cd_T"], dim["Cd_B"]
|
||||
Cl_F, Cl_T, Cl_B = dim["Cl_F"], dim["Cl_T"], dim["Cl_B"]
|
||||
|
||||
# If actions are in physical omega, convert to nondim alpha
|
||||
if alpha_mode:
|
||||
a = actions_prev.astype(np.float64)
|
||||
a2 = actions_prev2.astype(np.float64)
|
||||
else:
|
||||
a = actions_prev.astype(np.float64) / u0
|
||||
a2 = actions_prev2.astype(np.float64) / u0
|
||||
|
||||
sym = {}
|
||||
|
||||
# Sensor combinations (nondim)
|
||||
sym["u_m"] = (u_B + u_C + u_T) / 3.0
|
||||
sym["u_a"] = (u_T - u_B) / 2.0
|
||||
sym["u_c"] = u_C.copy()
|
||||
sym["v_a"] = (v_T - v_B) / 2.0
|
||||
|
||||
# Force combinations (dimensionless Cd/Cl)
|
||||
sym["Cd_tot"] = Cd_F + Cd_T + Cd_B
|
||||
sym["Cd_rear"] = Cd_T + Cd_B
|
||||
sym["Cl_tot"] = Cl_F + Cl_T + Cl_B
|
||||
sym["Cl_diff"] = Cl_T - Cl_B
|
||||
|
||||
# Phase (optional, may obscure linear structure)
|
||||
if include_cos_sin:
|
||||
sym["sin_ua"] = np.sin(np.pi * sym["u_a"])
|
||||
sym["cos_ua"] = np.cos(np.pi * sym["u_a"])
|
||||
|
||||
# Memory (nondim alpha) -- discrete version
|
||||
sym["aF_lag1"] = a[:, 0]
|
||||
sym["aB_lag1"] = a[:, 1]
|
||||
sym["aT_lag1"] = a[:, 2]
|
||||
sym["daF"] = a[:, 0] - a2[:, 0]
|
||||
sym["daB"] = a[:, 1] - a2[:, 1]
|
||||
sym["daT"] = a[:, 2] - a2[:, 2]
|
||||
|
||||
# Time-normalized deltas (for cross-scene coefficient comparison)
|
||||
sym["daF_dt"] = sym["daF"] / dt_c
|
||||
sym["daB_dt"] = sym["daB"] / dt_c
|
||||
sym["daT_dt"] = sym["daT"] / dt_c
|
||||
|
||||
# Target forces (for illusion scenes) — convert lattice forces to Cd/Cl
|
||||
if target_forces is not None:
|
||||
tf = np.asarray(target_forces, dtype=np.float64)
|
||||
if tf.ndim == 1:
|
||||
tf = tf.reshape(1, -1)
|
||||
sym["target_Cd"] = 2.0 * tf[:, 0] / (rho * u0**2 * D_CYL)
|
||||
sym["target_Cl"] = 2.0 * tf[:, 1] / (rho * u0**2 * D_CYL)
|
||||
# Error-state: deviation between actual and target force
|
||||
sym["Cd_err"] = sym["Cd_tot"] - sym["target_Cd"]
|
||||
sym["Cl_err"] = sym["Cl_tot"] - sym["target_Cl"]
|
||||
|
||||
# Mu modulation
|
||||
if include_mu:
|
||||
sym["mu"] = np.full(T, mu, dtype=np.float64)
|
||||
sym["mu_u_a"] = sym["u_a"] * mu
|
||||
sym["mu_v_a"] = sym["v_a"] * mu
|
||||
sym["mu_Cd_tot"] = sym["Cd_tot"] * mu
|
||||
sym["mu_Cl_diff"] = sym["Cl_diff"] * mu
|
||||
sym["mu_Cl_tot"] = sym["Cl_tot"] * mu # additional for phase-state
|
||||
|
||||
# Observation dynamics: 1-step lag + time-normalized derivative
|
||||
# These add temporal/phase info that static features lack.
|
||||
if sensors_raw is not None and forces_raw is not None:
|
||||
sr = np.asarray(sensors_raw, dtype=np.float64)
|
||||
fr = np.asarray(forces_raw, dtype=np.float64)
|
||||
# Lag-1 observations (shift by 1, pad first with current)
|
||||
s_lag1 = np.zeros_like(sr)
|
||||
f_lag1 = np.zeros_like(fr)
|
||||
s_lag1[1:] = sr[:-1]
|
||||
f_lag1[1:] = fr[:-1]
|
||||
# Compute dim for lag-1
|
||||
dim_lag1 = compute_dimensionless(s_lag1, f_lag1, u0=u0, d=D_CYL, rho=rho)
|
||||
|
||||
# Compute combined features for lag-1
|
||||
uB_1, uC_1, uT_1 = dim_lag1["u_hat_B"], dim_lag1["u_hat_C"], dim_lag1["u_hat_T"]
|
||||
vB_1, vC_1, vT_1 = dim_lag1["v_hat_B"], dim_lag1["v_hat_C"], dim_lag1["v_hat_T"]
|
||||
CdF_1, CdT_1, CdB_1 = dim_lag1["Cd_F"], dim_lag1["Cd_T"], dim_lag1["Cd_B"]
|
||||
ClF_1, ClT_1, ClB_1 = dim_lag1["Cl_F"], dim_lag1["Cl_T"], dim_lag1["Cl_B"]
|
||||
|
||||
u_m_1 = (uB_1 + uC_1 + uT_1) / 3.0
|
||||
u_a_1 = (uT_1 - uB_1) / 2.0
|
||||
u_c_1 = uC_1.copy()
|
||||
v_a_1 = (vT_1 - vB_1) / 2.0
|
||||
Cd_tot_1 = CdF_1 + CdT_1 + CdB_1
|
||||
Cd_rear_1 = CdT_1 + CdB_1
|
||||
Cl_tot_1 = ClF_1 + ClT_1 + ClB_1
|
||||
Cl_diff_1 = ClT_1 - ClB_1
|
||||
|
||||
# Trim to T (in case raw arrays are longer — e.g. validator passes 2 rows)
|
||||
def _trim(x):
|
||||
return x[-T:] if x.shape[0] > T else x
|
||||
|
||||
# Store lag-1 features (trimmed to T)
|
||||
sym["u_m_lag1"] = _trim(u_m_1)
|
||||
sym["u_a_lag1"] = _trim(u_a_1)
|
||||
sym["u_c_lag1"] = _trim(u_c_1)
|
||||
sym["v_a_lag1"] = _trim(v_a_1)
|
||||
sym["Cd_tot_lag1"] = _trim(Cd_tot_1)
|
||||
sym["Cd_rear_lag1"] = _trim(Cd_rear_1)
|
||||
sym["Cl_tot_lag1"] = _trim(Cl_tot_1)
|
||||
sym["Cl_diff_lag1"] = _trim(Cl_diff_1)
|
||||
|
||||
# Time-normalized derivatives: (current - lag1) / dt_c
|
||||
eps = 1e-12
|
||||
sym["du_m_dt"] = _trim((sym["u_m"] - u_m_1) / (dt_c + eps))
|
||||
sym["du_a_dt"] = _trim((sym["u_a"] - u_a_1) / (dt_c + eps))
|
||||
sym["du_c_dt"] = _trim((sym["u_c"] - u_c_1) / (dt_c + eps))
|
||||
sym["dv_a_dt"] = _trim((sym["v_a"] - v_a_1) / (dt_c + eps))
|
||||
sym["dCd_tot_dt"] = _trim((sym["Cd_tot"] - Cd_tot_1) / (dt_c + eps))
|
||||
sym["dCd_rear_dt"] = _trim((sym["Cd_rear"] - Cd_rear_1) / (dt_c + eps))
|
||||
sym["dCl_tot_dt"] = _trim((sym["Cl_tot"] - Cl_tot_1) / (dt_c + eps))
|
||||
sym["dCl_diff_dt"] = _trim((sym["Cl_diff"] - Cl_diff_1) / (dt_c + eps))
|
||||
|
||||
# Illusion error-state dynamics
|
||||
if target_forces is not None:
|
||||
tf = np.asarray(target_forces, dtype=np.float64)
|
||||
tf_lag1 = np.zeros_like(tf)
|
||||
tf_lag1[1:] = tf[:-1]
|
||||
tCd_1 = 2.0 * tf_lag1[:, 0] / (rho * u0**2 * D_CYL)
|
||||
tCl_1 = 2.0 * tf_lag1[:, 1] / (rho * u0**2 * D_CYL)
|
||||
sym["Cd_err_lag1"] = _trim(Cd_tot_1 - tCd_1)
|
||||
sym["Cl_err_lag1"] = _trim(Cl_tot_1 - tCl_1)
|
||||
sym["dCd_err_dt"] = _trim((sym["Cd_err"] - sym["Cd_err_lag1"]) / (dt_c + eps))
|
||||
sym["dCl_err_dt"] = _trim((sym["Cl_err"] - sym["Cl_err_lag1"]) / (dt_c + eps))
|
||||
|
||||
return sym
|
||||
|
||||
|
||||
def build_feature_matrix(
|
||||
sym: Dict[str, np.ndarray],
|
||||
feat_keys: List[str],
|
||||
add_bias: bool = True,
|
||||
) -> np.ndarray:
|
||||
"""Build feature matrix (T, N) from symbol dict."""
|
||||
cols = []
|
||||
if add_bias:
|
||||
cols.append(np.ones(sym[feat_keys[0]].shape[0], dtype=np.float64))
|
||||
for k in feat_keys:
|
||||
if k in sym:
|
||||
cols.append(np.asarray(sym[k], dtype=np.float64))
|
||||
else:
|
||||
# Missing key -> zero
|
||||
T = sym.get("u_m", np.ones(1)).shape[0]
|
||||
cols.append(np.zeros(T, dtype=np.float64))
|
||||
return np.column_stack(cols)
|
||||
|
||||
|
||||
def get_feature_names(feat_keys: List[str], add_bias: bool = True) -> List[str]:
|
||||
"""Get feature names matching build_feature_matrix output."""
|
||||
names = []
|
||||
if add_bias:
|
||||
names.append("bias")
|
||||
names.extend(feat_keys)
|
||||
return names
|
||||
@@ -0,0 +1,503 @@
|
||||
"""SINDy fitting utilities: STLSQ threshold grid, feature matrix building.
|
||||
|
||||
All features are built using the unified feature_builder module.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .feature_builder import (
|
||||
compute_dimensionless, compute_features, build_feature_matrix,
|
||||
get_feature_names, ALL_FEAT_KEYS, U0,
|
||||
)
|
||||
|
||||
# Default thresholds used across all scenes
|
||||
DEFAULT_THRESHOLDS = [0.0, 0.001, 0.002, 0.005, 0.01, 0.015, 0.02, 0.03, 0.05, 0.1]
|
||||
|
||||
|
||||
def fit_channel(
|
||||
Theta: np.ndarray,
|
||||
y: np.ndarray,
|
||||
thresholds: Optional[List[float]] = None,
|
||||
alpha: float = 1e-4,
|
||||
max_iter: int = 25,
|
||||
) -> Tuple[List[dict], dict]:
|
||||
"""Fit a single channel (one cylinder) with STLSQ threshold grid.
|
||||
|
||||
Returns
|
||||
-------
|
||||
rows : list of dict per threshold
|
||||
best : dict with best threshold entry (highest R2)
|
||||
"""
|
||||
import pysindy as ps
|
||||
|
||||
if thresholds is None:
|
||||
thresholds = DEFAULT_THRESHOLDS
|
||||
|
||||
# Normalise features for thresholding stability
|
||||
std = np.std(Theta, axis=0)
|
||||
std = np.where(std < 1e-8, 1.0, std)
|
||||
Theta_s = Theta / std
|
||||
|
||||
best = None
|
||||
rows = []
|
||||
for th in thresholds:
|
||||
opt = ps.STLSQ(threshold=th, alpha=alpha, max_iter=max_iter)
|
||||
opt.fit(Theta_s, y)
|
||||
coef = np.asarray(opt.coef_, dtype=np.float64).flatten() / std
|
||||
y_pred = Theta @ coef
|
||||
ssr = float(np.sum((y - y_pred) ** 2))
|
||||
sst = float(np.sum((y - np.mean(y)) ** 2) + 1e-12)
|
||||
r2 = 1.0 - ssr / sst
|
||||
mae = float(np.mean(np.abs(y - y_pred)))
|
||||
nz = int(np.sum(np.abs(coef) > 1e-8))
|
||||
entry = {"threshold": float(th), "nz": nz, "r2": r2, "mae": mae, "coef": coef}
|
||||
rows.append(entry)
|
||||
if best is None or r2 > best["r2"]:
|
||||
best = entry
|
||||
return rows, best
|
||||
|
||||
|
||||
def fit_sindy(
|
||||
Theta: np.ndarray,
|
||||
y: np.ndarray,
|
||||
thresholds: Optional[List[float]] = None,
|
||||
) -> List[dict]:
|
||||
"""Run SINDy with threshold grid, return results list.
|
||||
|
||||
Each result dict has keys: threshold, nz, r2, mae, coef.
|
||||
"""
|
||||
if thresholds is None:
|
||||
thresholds = DEFAULT_THRESHOLDS
|
||||
|
||||
std = np.std(Theta, axis=0)
|
||||
std = np.where(std < 1e-8, 1.0, std)
|
||||
Theta_s = Theta / std
|
||||
|
||||
results = []
|
||||
for th in thresholds:
|
||||
import pysindy as ps
|
||||
opt = ps.STLSQ(threshold=th, alpha=1e-4, max_iter=25)
|
||||
opt.fit(Theta_s, y)
|
||||
coef = np.asarray(opt.coef_, dtype=np.float64).flatten() / std
|
||||
|
||||
y_pred = Theta @ coef
|
||||
ssr = float(np.sum((y - y_pred) ** 2))
|
||||
sst = float(np.sum((y - np.mean(y)) ** 2) + 1e-12)
|
||||
r2 = 1.0 - ssr / sst
|
||||
mae = float(np.mean(np.abs(y - y_pred)))
|
||||
nz = int(np.sum(np.abs(coef) > 1e-8))
|
||||
|
||||
results.append({
|
||||
"threshold": float(th), "nz": nz, "r2": r2,
|
||||
"mae": mae, "coef": [float(c) for c in coef],
|
||||
})
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def print_control_law(feature_names: List[str], coef: np.ndarray, channel_label: str = "ch"):
|
||||
"""Pretty-print a sparse control law."""
|
||||
terms = []
|
||||
for i, c in enumerate(coef):
|
||||
if abs(c) > 1e-8:
|
||||
terms.append(f"{c:.6f} * {feature_names[i]}")
|
||||
print(f" {channel_label}: {' + '.join(terms)}")
|
||||
nz = sum(1 for c in coef if abs(c) > 1e-8)
|
||||
print(f" non-zero terms: {nz}")
|
||||
|
||||
|
||||
def get_active_support(
|
||||
coef: np.ndarray,
|
||||
feat_names: List[str],
|
||||
relative_threshold: float = 0.02,
|
||||
) -> Dict[str, float]:
|
||||
"""Extract active features from coefficient vector.
|
||||
|
||||
Features with |coef| / max(|coef|) >= relative_threshold are considered active.
|
||||
"""
|
||||
max_c = np.max(np.abs(coef))
|
||||
if max_c < 1e-12:
|
||||
return {}
|
||||
active = {}
|
||||
for name, c in zip(feat_names, coef):
|
||||
if abs(c) / max_c >= relative_threshold:
|
||||
active[name] = float(c)
|
||||
return active
|
||||
|
||||
|
||||
def get_feature_matrix_from_data(
|
||||
sensors: np.ndarray, # (T, 6)
|
||||
forces: np.ndarray, # (T, 6)
|
||||
actions_phys: np.ndarray, # (T, 3) physical omega
|
||||
mu: float,
|
||||
u0: float = U0,
|
||||
alpha_mode: bool = False,
|
||||
include_mu: bool = True,
|
||||
n_warmup: int = 2,
|
||||
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, List[str], List[str]]:
|
||||
"""Build feature matrices from raw CFD data.
|
||||
|
||||
Constructs dimensionless features via feature_builder, creates front (no bias)
|
||||
and rear (with bias) feature matrices, and returns them aligned with Y.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
sensors, forces, actions_phys : raw data arrays.
|
||||
mu : 1/Re_D.
|
||||
u0 : inlet velocity (lattice units).
|
||||
alpha_mode : if True, actions_phys are already nondim alpha.
|
||||
include_mu : include mu modulation features.
|
||||
n_warmup : number of warmup steps to discard (default 2 for lag/da).
|
||||
|
||||
Returns
|
||||
-------
|
||||
Theta_front : (T-warmup, N_front) feature matrix, NO bias column
|
||||
Theta_rear : (T-warmup, N_rear) feature matrix, WITH bias column
|
||||
Y : (T-warmup, 3) target action matrix
|
||||
feat_names_front : list of feature names for front
|
||||
feat_names_rear : list of feature names for rear
|
||||
"""
|
||||
T = sensors.shape[0]
|
||||
a_prev = np.zeros((T, 3), dtype=np.float64)
|
||||
a_prev2 = np.zeros((T, 3), dtype=np.float64)
|
||||
a_prev[1:] = actions_phys[:-1]
|
||||
a_prev2[2:] = actions_phys[:-2]
|
||||
|
||||
dim = compute_dimensionless(sensors, forces, u0=u0, d=20.0)
|
||||
sym = compute_features(dim, a_prev, a_prev2, mu,
|
||||
alpha_mode=alpha_mode, include_mu=include_mu, u0=u0)
|
||||
|
||||
Theta_f = build_feature_matrix(sym, ALL_FEAT_KEYS, add_bias=False)
|
||||
Theta_r = build_feature_matrix(sym, ALL_FEAT_KEYS, add_bias=True)
|
||||
|
||||
feat_names_front = get_feature_names(ALL_FEAT_KEYS, add_bias=False)
|
||||
feat_names_rear = get_feature_names(ALL_FEAT_KEYS, add_bias=True)
|
||||
|
||||
return (Theta_f[n_warmup:], Theta_r[n_warmup:],
|
||||
actions_phys[n_warmup:],
|
||||
feat_names_front, feat_names_rear)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Weighted STLSQ with Huber-like robust regression
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _huber_weights(residuals: np.ndarray, c: float = 1.345) -> np.ndarray:
|
||||
"""Compute Huber-like weights from residuals.
|
||||
|
||||
Args:
|
||||
residuals: (T,) residual array.
|
||||
c: tuning constant (default 1.345 gives 95% efficiency for Normal errors).
|
||||
|
||||
Returns:
|
||||
weights: (T,) weight array in [0, 1].
|
||||
"""
|
||||
s = np.median(np.abs(residuals)) * 1.4826 # robust scale estimate (MAD)
|
||||
if s < 1e-12:
|
||||
s = 1.0
|
||||
r = np.abs(residuals) / s
|
||||
w = np.where(r <= c, 1.0, c / r)
|
||||
return np.asarray(w, dtype=np.float64)
|
||||
|
||||
|
||||
def fit_sindy_weighted(
|
||||
Theta: np.ndarray,
|
||||
y: np.ndarray,
|
||||
thresholds: Optional[List[float]] = None,
|
||||
alpha: float = 1e-4,
|
||||
max_iter: int = 25,
|
||||
sample_weights: Optional[np.ndarray] = None,
|
||||
n_robust_passes: int = 2,
|
||||
) -> List[dict]:
|
||||
"""Run SINDy with threshold grid and optional robust weighting.
|
||||
|
||||
Two-stage robust fitting:
|
||||
1. First pass: OLS, compute residuals, compute Huber weights
|
||||
2. Second pass: weighted STLSQ with Huber weights
|
||||
|
||||
Args:
|
||||
Theta: (T, N) feature matrix.
|
||||
y: (T,) target.
|
||||
thresholds: list of threshold values.
|
||||
alpha: ridge regularization.
|
||||
max_iter: max STLSQ iterations.
|
||||
sample_weights: optional (T,) pre-defined sample weights.
|
||||
n_robust_passes: number of robust re-weighting passes (1 = skip).
|
||||
|
||||
Returns:
|
||||
results: list of dict per threshold with keys:
|
||||
threshold, nz, r2, mae, coef, weights_used
|
||||
"""
|
||||
import pysindy as ps
|
||||
|
||||
if thresholds is None:
|
||||
thresholds = DEFAULT_THRESHOLDS
|
||||
|
||||
# Normalise features for thresholding stability
|
||||
std = np.std(Theta, axis=0)
|
||||
std = np.where(std < 1e-8, 1.0, std)
|
||||
Theta_s = Theta / std
|
||||
|
||||
# Initialize weights
|
||||
if sample_weights is not None:
|
||||
w = np.asarray(sample_weights, dtype=np.float64).flatten()
|
||||
w = w / np.mean(w) # normalize to mean=1
|
||||
else:
|
||||
w = np.ones(Theta.shape[0], dtype=np.float64)
|
||||
|
||||
# Robust re-weighting passes
|
||||
for _ in range(n_robust_passes - 1):
|
||||
# OLS on weighted data
|
||||
Theta_w = Theta_s * np.sqrt(w)[:, None]
|
||||
y_w = y * np.sqrt(w)
|
||||
coef_ols, _, _, _ = np.linalg.lstsq(Theta_w, y_w, rcond=None)
|
||||
coef_ols = coef_ols.flatten() / std
|
||||
|
||||
resid = y - Theta @ coef_ols
|
||||
w_new = _huber_weights(resid)
|
||||
if sample_weights is not None:
|
||||
w = w * w_new
|
||||
else:
|
||||
w = w_new
|
||||
w = w / np.mean(w)
|
||||
|
||||
results = []
|
||||
for th in thresholds:
|
||||
if np.max(w) > 1e-8:
|
||||
# Weighted STLSQ: apply weights via sample_weight
|
||||
opt = ps.STLSQ(threshold=th, alpha=alpha, max_iter=max_iter)
|
||||
opt.fit(Theta_s, y, sample_weight=w)
|
||||
coef = np.asarray(opt.coef_, dtype=np.float64).flatten() / std
|
||||
else:
|
||||
coef = np.zeros(Theta.shape[1], dtype=np.float64)
|
||||
|
||||
y_pred = Theta @ coef
|
||||
# Weighted R2
|
||||
ssr = float(np.sum(w * (y - y_pred) ** 2))
|
||||
sst = float(np.sum(w * (y - np.average(y, weights=w)) ** 2) + 1e-12)
|
||||
r2 = 1.0 - ssr / sst
|
||||
mae = float(np.mean(np.abs(y - y_pred)))
|
||||
nz = int(np.sum(np.abs(coef) > 1e-8))
|
||||
|
||||
results.append({
|
||||
"threshold": float(th),
|
||||
"nz": nz,
|
||||
"r2": r2,
|
||||
"mae": mae,
|
||||
"coef": [float(c) for c in coef],
|
||||
"weights_min": float(np.min(w)),
|
||||
"weights_max": float(np.max(w)),
|
||||
})
|
||||
|
||||
return results
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# V2 feature matrix builder (configurable feature sets, time normalization)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def get_feature_matrix_v2(
|
||||
sensors: np.ndarray, # (T, 6)
|
||||
forces: np.ndarray, # (T, 6)
|
||||
actions_phys: np.ndarray, # (T, 3) physical omega
|
||||
mu: float,
|
||||
u0: float = U0,
|
||||
alpha_mode: bool = False,
|
||||
include_mu: bool = False, # default False for single-scene
|
||||
include_cos_sin: bool = False, # default False (avoid masking linear structure)
|
||||
use_time_norm: bool = False, # if True, use time-normalized deltas (da/dt_c)
|
||||
feat_keys: Optional[List[str]] = None, # custom feat keys (default CORE_FEAT_KEYS_V2)
|
||||
dt_c: float = 1.0, # control interval in T0 units
|
||||
n_warmup: int = 2,
|
||||
target_forces: Optional[np.ndarray] = None, # (T, 2) raw lattice target forces
|
||||
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, List[str], List[str]]:
|
||||
"""Build feature matrices with configurable feature sets.
|
||||
|
||||
Uses CORE_FEAT_KEYS_V2 by default (no sin_ua/cos_ua, no mu).
|
||||
For Illusion scenes with target forces, provide target_forces and
|
||||
feat_keys=ILLUSION_FEAT_KEYS_V2 (or pass None to auto-detect).
|
||||
For cross-Re joint fitting, set include_mu=True.
|
||||
For time-normalized deltas, set use_time_norm=True and provide dt_c.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Theta_front : (T-warmup, N_front) NO bias column
|
||||
Theta_rear : (T-warmup, N_rear) WITH bias column
|
||||
Y : (T-warmup, 3) target actions (physical omega)
|
||||
feat_names_front, feat_names_rear
|
||||
"""
|
||||
from .feature_builder import (
|
||||
CORE_FEAT_KEYS_V2, TIME_FEAT_KEYS, MU_FEAT_KEYS, ALL_FEAT_KEYS_V2,
|
||||
ILLUSION_FEAT_KEYS_V2, ILLUSION_ALL_FEAT_KEYS_V2,
|
||||
)
|
||||
|
||||
if feat_keys is None:
|
||||
if target_forces is not None:
|
||||
# Illusion scenes: include target force features
|
||||
feat_keys = ILLUSION_FEAT_KEYS_V2
|
||||
elif use_time_norm:
|
||||
# Replace discrete da with time-normalized da/dt
|
||||
feat_keys = [k for k in CORE_FEAT_KEYS_V2 if not k.startswith("da")]
|
||||
feat_keys += TIME_FEAT_KEYS
|
||||
else:
|
||||
feat_keys = CORE_FEAT_KEYS_V2
|
||||
|
||||
if include_mu:
|
||||
# Add mu features if not already in feat_keys
|
||||
for mk in MU_FEAT_KEYS:
|
||||
if mk not in feat_keys:
|
||||
feat_keys = feat_keys + [mk]
|
||||
|
||||
T = sensors.shape[0]
|
||||
a_prev = np.zeros((T, 3), dtype=np.float64)
|
||||
a_prev2 = np.zeros((T, 3), dtype=np.float64)
|
||||
a_prev[1:] = actions_phys[:-1]
|
||||
a_prev2[2:] = actions_phys[:-2]
|
||||
|
||||
dim = compute_dimensionless(sensors, forces, u0=u0, d=20.0)
|
||||
sym = compute_features(
|
||||
dim, a_prev, a_prev2, mu,
|
||||
alpha_mode=alpha_mode,
|
||||
include_mu=include_mu,
|
||||
include_cos_sin=include_cos_sin,
|
||||
dt_c=dt_c,
|
||||
u0=u0,
|
||||
target_forces=target_forces,
|
||||
)
|
||||
|
||||
Theta_f = build_feature_matrix(sym, feat_keys, add_bias=False)
|
||||
Theta_r = build_feature_matrix(sym, feat_keys, add_bias=True)
|
||||
|
||||
feat_names_front = get_feature_names(feat_keys, add_bias=False)
|
||||
feat_names_rear = get_feature_names(feat_keys, add_bias=True)
|
||||
|
||||
return (Theta_f[n_warmup:], Theta_r[n_warmup:],
|
||||
actions_phys[n_warmup:],
|
||||
feat_names_front, feat_names_rear)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Derivative-mode feature builders: fit d(alpha)/dt = g(physics_state)
|
||||
# No action history in input features; Y is time-normalized action derivative.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def compute_action_deriv(
|
||||
actions_phys: np.ndarray, # (T, 3) physical omega
|
||||
dt_c: float, # control interval in T0 units
|
||||
u0: float = U0,
|
||||
center_diff: bool = False, # if True, use (alpha(t) - alpha(t-2))/(2*dt_c)
|
||||
) -> np.ndarray:
|
||||
"""Compute time-normalized action derivative d(alpha)/dt.
|
||||
|
||||
forward_diff: d(alpha)/dt ~ (alpha(t) - alpha(t-1)) / dt_c
|
||||
center_diff: d(alpha)/dt ~ (alpha(t) - alpha(t-2)) / (2*dt_c)
|
||||
|
||||
Returns (T, 3) array, with first row(s) zero-padded.
|
||||
"""
|
||||
alpha = np.asarray(actions_phys, dtype=np.float64) / u0 # non-dim
|
||||
T = alpha.shape[0]
|
||||
deriv = np.zeros_like(alpha)
|
||||
if center_diff and T >= 3:
|
||||
deriv[2:] = (alpha[2:] - alpha[:-2]) / (2.0 * dt_c)
|
||||
elif T >= 2:
|
||||
deriv[1:] = (alpha[1:] - alpha[:-1]) / dt_c
|
||||
return deriv
|
||||
|
||||
|
||||
def get_feature_matrix_deriv(
|
||||
sensors: np.ndarray, # (T, 6)
|
||||
forces: np.ndarray, # (T, 6)
|
||||
actions_phys: np.ndarray, # (T, 3) physical omega
|
||||
mu: float,
|
||||
u0: float = U0,
|
||||
dt_c: float = 1.0, # control interval in T0 units
|
||||
feat_keys: Optional[List[str]] = None, # default PHYSICS_FEAT_KEYS
|
||||
include_mu: bool = False, # add mu modulation features (for cross-Re joint)
|
||||
target_forces: Optional[np.ndarray] = None, # (T, 2) for Illusion
|
||||
n_warmup: int = 2,
|
||||
center_diff: bool = False,
|
||||
augment_level: int = 0, # 0=static, 1=+lags, 2=+derivs, 3=both, 4=+action_lag
|
||||
output_mode: str = "deriv", # "deriv": predict d(alpha)/dt; "absolute": predict alpha directly
|
||||
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, List[str], List[str]]:
|
||||
"""Build feature matrices for phase-state SINDy.
|
||||
|
||||
Input features: physics state with optional temporal context.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
output_mode : str
|
||||
"deriv": Y = d(alpha)/dt (time-normalized). Closed-loop needs integration.
|
||||
"absolute": Y = alpha (non-dimensional action). No integration needed.
|
||||
|
||||
augment_level : int
|
||||
0: PHYSICS_FEAT_KEYS only (static, no memory)
|
||||
1: + lag-1 obs features (adds temporal context)
|
||||
2: + obs derivative features (adds rate information)
|
||||
3: + lag-1 + derivative (full temporal context)
|
||||
4: + action lag (aF_lag1 etc., for ablation comparison against old approach)
|
||||
"""
|
||||
from .feature_builder import (
|
||||
PHYSICS_FEAT_KEYS, ILLUSION_ERR_KEYS, MU_FEAT_KEYS,
|
||||
AUG_LEVEL_1_KEYS, AUG_LEVEL_2_KEYS,
|
||||
AUG_LEVEL_3_KEYS, AUG_LEVEL_4_KEYS,
|
||||
ILLUSION_AUG_LEVEL_1_KEYS, ILLUSION_AUG_LEVEL_2_KEYS,
|
||||
ILLUSION_AUG_LEVEL_3_KEYS, ILLUSION_AUG_LEVEL_4_KEYS,
|
||||
)
|
||||
|
||||
# Select feature key set based on augment_level
|
||||
_AUG_MAP = {0: PHYSICS_FEAT_KEYS, 1: AUG_LEVEL_1_KEYS,
|
||||
2: AUG_LEVEL_2_KEYS, 3: AUG_LEVEL_3_KEYS, 4: AUG_LEVEL_4_KEYS}
|
||||
_AUG_ILLUSION_MAP = {0: ILLUSION_ERR_KEYS, 1: ILLUSION_AUG_LEVEL_1_KEYS,
|
||||
2: ILLUSION_AUG_LEVEL_2_KEYS, 3: ILLUSION_AUG_LEVEL_3_KEYS,
|
||||
4: ILLUSION_AUG_LEVEL_4_KEYS}
|
||||
|
||||
if feat_keys is None:
|
||||
if target_forces is not None:
|
||||
feat_keys = _AUG_ILLUSION_MAP.get(augment_level, ILLUSION_AUG_LEVEL_3_KEYS)
|
||||
else:
|
||||
feat_keys = _AUG_MAP.get(augment_level, AUG_LEVEL_3_KEYS)
|
||||
|
||||
if include_mu:
|
||||
for mk in MU_FEAT_KEYS:
|
||||
if mk not in feat_keys:
|
||||
feat_keys = feat_keys + [mk]
|
||||
|
||||
if include_mu:
|
||||
for mk in MU_FEAT_KEYS:
|
||||
if mk not in feat_keys:
|
||||
feat_keys = feat_keys + [mk]
|
||||
|
||||
T = sensors.shape[0]
|
||||
# a_prev/a_prev2 only used for computing the DERIVATIVE target Y, not in Theta
|
||||
a_prev = np.zeros((T, 3), dtype=np.float64)
|
||||
a_prev2 = np.zeros((T, 3), dtype=np.float64)
|
||||
a_prev[1:] = actions_phys[:-1]
|
||||
a_prev2[2:] = actions_phys[:-2]
|
||||
|
||||
dim = compute_dimensionless(sensors, forces, u0=u0, d=20.0)
|
||||
sym = compute_features(
|
||||
dim, a_prev, a_prev2, mu,
|
||||
alpha_mode=False, include_mu=include_mu,
|
||||
include_cos_sin=False, dt_c=dt_c, u0=u0,
|
||||
target_forces=target_forces,
|
||||
sensors_raw=sensors, forces_raw=forces,
|
||||
)
|
||||
|
||||
Theta_f = build_feature_matrix(sym, feat_keys, add_bias=False)
|
||||
Theta_r = build_feature_matrix(sym, feat_keys, add_bias=True)
|
||||
|
||||
feat_names_front = get_feature_names(feat_keys, add_bias=False)
|
||||
feat_names_rear = get_feature_names(feat_keys, add_bias=True)
|
||||
|
||||
# Y: depends on output_mode
|
||||
if output_mode == "absolute":
|
||||
Y = np.asarray(actions_phys, dtype=np.float64) / u0 # non-dim alpha (absolute action)
|
||||
else:
|
||||
Y = compute_action_deriv(actions_phys, dt_c, u0=u0, center_diff=center_diff)
|
||||
|
||||
return (Theta_f[n_warmup:], Theta_r[n_warmup:],
|
||||
Y[n_warmup:],
|
||||
feat_names_front, feat_names_rear)
|
||||
@@ -0,0 +1,191 @@
|
||||
"""G-operator and equivariance tools.
|
||||
|
||||
Provides G-operator transformations, dimensionless conversion,
|
||||
and equivariance diagnostics for PPO control laws.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict, Optional, Tuple
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .feature_builder import compute_dimensionless as _compute_dimless
|
||||
|
||||
|
||||
def apply_G_alpha(alpha: np.ndarray) -> np.ndarray:
|
||||
"""Apply mirror G to action: [aF, aT, aB] -> [-aF, -aB, -aT]."""
|
||||
return np.array([-alpha[0], -alpha[2], -alpha[1]], dtype=alpha.dtype)
|
||||
|
||||
|
||||
def apply_G_raw(obs_slice: np.ndarray,
|
||||
a_prev: np.ndarray,
|
||||
a_prev2: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
||||
"""Apply G to raw obs slice [sensor(6)+force(6)] and action arrays.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
obs_slice : (12,) raw obs [s0_ux,uy, s1_ux,uy, s2_ux,uy, f0_fx,fy, f1_fx,fy, f2_fx,fy]
|
||||
a_prev : (3,) physical omega at t-1
|
||||
a_prev2 : (3,) physical omega at t-2
|
||||
|
||||
Returns
|
||||
-------
|
||||
G_obs : (12,) transformed obs slice
|
||||
G_a_prev : (3,) transformed a_prev
|
||||
G_a_prev2 : (3,) transformed a_prev2
|
||||
"""
|
||||
G_obs = np.zeros(12, dtype=np.float64)
|
||||
# sensors: swap top(0,1) <-> bottom(4,5), negate v
|
||||
G_obs[0] = obs_slice[4]
|
||||
G_obs[1] = -obs_slice[5]
|
||||
G_obs[2] = obs_slice[2]
|
||||
G_obs[3] = -obs_slice[3]
|
||||
G_obs[4] = obs_slice[0]
|
||||
G_obs[5] = -obs_slice[1]
|
||||
# forces: swap bottom(2,3) <-> top(4,5), negate fy
|
||||
G_obs[6] = obs_slice[6]
|
||||
G_obs[7] = -obs_slice[7]
|
||||
G_obs[8] = obs_slice[10]
|
||||
G_obs[9] = -obs_slice[11]
|
||||
G_obs[10] = obs_slice[8]
|
||||
G_obs[11] = -obs_slice[9]
|
||||
|
||||
G_a_prev = np.array([-a_prev[0], -a_prev[2], -a_prev[1]], dtype=np.float64)
|
||||
G_a_prev2 = np.array([-a_prev2[0], -a_prev2[2], -a_prev2[1]], dtype=np.float64)
|
||||
return G_obs, G_a_prev, G_a_prev2
|
||||
|
||||
|
||||
def check_equivariance(
|
||||
model: Any,
|
||||
obs_slice_series: np.ndarray, # (T, 12) raw obs
|
||||
actions_phys: np.ndarray, # (T, 3) physical omega
|
||||
norm: dict,
|
||||
action_scale: float = 8.0,
|
||||
action_bias: Tuple[float, float, float] = (0.0, -4.0, 4.0),
|
||||
u0: float = 0.01,
|
||||
) -> Dict[str, float]:
|
||||
"""Check G-equivariance of a PPO model over a time series.
|
||||
|
||||
Returns dict with front/rear equivariance errors.
|
||||
"""
|
||||
from .cfd_interface import build_observation, action_to_physical
|
||||
|
||||
T = min(obs_slice_series.shape[0], actions_phys.shape[0])
|
||||
ef, eb, et = [], [], []
|
||||
|
||||
for t in range(2, T):
|
||||
# Get current obs
|
||||
osl = obs_slice_series[t]
|
||||
a_prev = actions_phys[t - 1] if t > 0 else actions_phys[0]
|
||||
a_prev2 = actions_phys[t - 2] if t > 1 else actions_phys[0]
|
||||
|
||||
# Predict action for current state
|
||||
obs = build_observation(osl, norm)
|
||||
act, _ = model.predict(obs, deterministic=True)
|
||||
act = act.astype(np.float32).flatten()
|
||||
alpha = action_to_physical(act.reshape(1, 3),
|
||||
scale=action_scale, bias=action_bias, u0=u0).flatten()
|
||||
|
||||
# Apply G to state
|
||||
G_obs, _, _ = apply_G_raw(osl, a_prev, a_prev2)
|
||||
obs_G = build_observation(G_obs, norm)
|
||||
act_G, _ = model.predict(obs_G, deterministic=True)
|
||||
act_G = act_G.astype(np.float32).flatten()
|
||||
alpha_G = action_to_physical(act_G.reshape(1, 3),
|
||||
scale=action_scale, bias=action_bias, u0=u0).flatten()
|
||||
|
||||
# Expected: G(alpha) = [-aF, -aB, -aT]
|
||||
expected = apply_G_alpha(alpha)
|
||||
|
||||
ef.append(abs(float(alpha_G[0]) - float(expected[0])))
|
||||
eb.append(abs(float(alpha_G[1]) - float(expected[1])))
|
||||
et.append(abs(float(alpha_G[2]) - float(expected[2])))
|
||||
|
||||
ef_arr = np.array(ef)
|
||||
eb_arr = np.array(eb)
|
||||
et_arr = np.array(et)
|
||||
alpha_range = float(np.max(np.abs(actions_phys[2:])))
|
||||
|
||||
return {
|
||||
"front_mean_abs_error": float(np.mean(ef_arr)),
|
||||
"front_rel_error": float(np.mean(ef_arr) / (alpha_range + 1e-12)),
|
||||
"rear_bottom_rel_error": float(np.mean(eb_arr) / (alpha_range + 1e-12)),
|
||||
"rear_top_rel_error": float(np.mean(et_arr) / (alpha_range + 1e-12)),
|
||||
"alpha_range": alpha_range,
|
||||
}
|
||||
|
||||
|
||||
def diagnose_one_re(model, ff, target_states, norm, config, n_steps=150) -> dict:
|
||||
"""Run PPO inference and check equivariance.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
model : loaded PPO model
|
||||
ff : FlowField instance (must be at saved checkpoint state)
|
||||
target_states : (FIFO_LEN, 6) target sensor signals
|
||||
norm : norm dict
|
||||
config : scene config dict with action_scale, action_bias, u0, etc.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict with equivariance metrics.
|
||||
"""
|
||||
from collections import deque
|
||||
from .cfd_interface import (build_observation, scale_action,
|
||||
action_to_physical, compute_similarity)
|
||||
|
||||
action_scale = config.get("action_scale", 8.0)
|
||||
action_bias = config.get("action_bias", (0.0, -4.0, 4.0))
|
||||
u0 = config.get("u0", 0.01)
|
||||
sample_interval = config.get("sample_interval", 800)
|
||||
fifo_len = config.get("fifo_len", 150)
|
||||
n_obj_total = config.get("n_objects_total", 7)
|
||||
|
||||
ff.restore_ddf()
|
||||
ff.apply_ddf()
|
||||
|
||||
# Bias FIFO init
|
||||
fifo = deque(maxlen=fifo_len)
|
||||
bias_arr = scale_action(np.zeros(3, dtype=np.float32),
|
||||
scale=action_scale, bias=action_bias,
|
||||
u0=u0, n_total_bodies=n_obj_total)
|
||||
for _ in range(fifo_len):
|
||||
ff.run(sample_interval, bias_arr)
|
||||
fifo.append(ff.obs.copy()[2:14])
|
||||
|
||||
# Inference
|
||||
obs_array = []
|
||||
action_array = []
|
||||
obs = np.zeros(12, dtype=np.float32)
|
||||
|
||||
for _ in range(n_steps):
|
||||
act, _ = model.predict(obs, deterministic=True)
|
||||
act = act.astype(np.float32).flatten()
|
||||
action_array.append(act.copy())
|
||||
|
||||
action_arr = scale_action(act, scale=action_scale, bias=action_bias,
|
||||
u0=u0, n_total_bodies=n_obj_total)
|
||||
ff.context.push()
|
||||
ff.run(sample_interval, action_arr)
|
||||
ff.context.pop()
|
||||
|
||||
obs_slice = ff.obs.copy()[2:14]
|
||||
fifo.append(obs_slice)
|
||||
obs_array.append(obs_slice)
|
||||
obs = build_observation(obs_slice, norm)
|
||||
|
||||
obs_series = np.array(obs_array, dtype=np.float64)
|
||||
actions_phys = action_to_physical(np.array(action_array),
|
||||
scale=action_scale, bias=action_bias, u0=u0)
|
||||
states_arr = np.array(list(fifo), dtype=np.float32)
|
||||
sim = compute_similarity(target_states, states_arr[:, 0:6],
|
||||
config.get("conv_len", 30))
|
||||
|
||||
# Equivariance check
|
||||
eq = check_equivariance(model, obs_series, actions_phys, norm,
|
||||
action_scale, action_bias, u0)
|
||||
|
||||
return {
|
||||
"similarity": sim,
|
||||
"equivariance": eq,
|
||||
}
|
||||
|
After Width: | Height: | Size: 412 KiB |
|
After Width: | Height: | Size: 189 KiB |
|
After Width: | Height: | Size: 234 KiB |
|
After Width: | Height: | Size: 169 KiB |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 167 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 299 KiB |
|
After Width: | Height: | Size: 151 KiB |
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"dc": 0.0029594360229869684,
|
||||
"amps": [
|
||||
4.482508629307246e-06,
|
||||
1.7559728832214555e-06,
|
||||
1.695399969073208e-06,
|
||||
4.863359419766791e-07,
|
||||
4.0744896335315875e-07
|
||||
],
|
||||
"freqs": [
|
||||
0.08666666666666667,
|
||||
0.18000000000000002,
|
||||
0.09333333333333334,
|
||||
0.1,
|
||||
0.08
|
||||
],
|
||||
"phases": [
|
||||
-2.223160683015736,
|
||||
-3.090016544658663,
|
||||
-1.4396296733151448,
|
||||
-1.3066393251376214,
|
||||
1.6772756869554482
|
||||
]
|
||||
},
|
||||
{
|
||||
"dc": 1.3870471496678268e-05,
|
||||
"amps": [
|
||||
0.00028510443996025985,
|
||||
0.0002599505102795033,
|
||||
9.365825828740738e-05,
|
||||
8.877059656510341e-05,
|
||||
5.6681594533049977e-05
|
||||
],
|
||||
"freqs": [
|
||||
0.04666666666666667,
|
||||
0.04,
|
||||
0.05333333333333334,
|
||||
0.03333333333333333,
|
||||
0.060000000000000005
|
||||
],
|
||||
"phases": [
|
||||
-2.111421674988832,
|
||||
0.931445743532081,
|
||||
-2.026139500541211,
|
||||
0.8174729094507539,
|
||||
-1.9494987485100541
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"dc": 0.0034837019443511963,
|
||||
"amps": [
|
||||
1.1376483917607967e-05,
|
||||
7.248102177867125e-06,
|
||||
5.838593601492066e-06,
|
||||
3.099357973227853e-06,
|
||||
2.721364398772006e-06
|
||||
],
|
||||
"freqs": [
|
||||
0.08,
|
||||
0.07333333333333333,
|
||||
0.09333333333333334,
|
||||
0.18000000000000002,
|
||||
0.1
|
||||
],
|
||||
"phases": [
|
||||
-1.0408841490876113,
|
||||
1.9485158983384934,
|
||||
-1.3904977741558484,
|
||||
2.7148922736497454,
|
||||
-1.2577909435667654
|
||||
]
|
||||
},
|
||||
{
|
||||
"dc": 2.0249660774425138e-05,
|
||||
"amps": [
|
||||
0.0006472307684973089,
|
||||
0.0001580755533972986,
|
||||
9.359867367951902e-05,
|
||||
7.772244469336163e-05,
|
||||
5.558302481685001e-05
|
||||
],
|
||||
"freqs": [
|
||||
0.04,
|
||||
0.03333333333333333,
|
||||
0.04666666666666667,
|
||||
0.02666666666666667,
|
||||
0.02
|
||||
],
|
||||
"phases": [
|
||||
3.026701709868741,
|
||||
-0.09658000009988132,
|
||||
3.0095201121212978,
|
||||
-0.07819925121021988,
|
||||
-0.05948277368734109
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"dc": 0.004293269868940115,
|
||||
"amps": [
|
||||
3.8063591256693715e-05,
|
||||
8.663235430632004e-06,
|
||||
7.901108470774483e-06,
|
||||
7.1510384113964075e-06,
|
||||
6.272449978203118e-06
|
||||
],
|
||||
"freqs": [
|
||||
0.06666666666666667,
|
||||
0.09333333333333334,
|
||||
0.08666666666666667,
|
||||
0.18000000000000002,
|
||||
0.006666666666666667
|
||||
],
|
||||
"phases": [
|
||||
2.9599042697964997,
|
||||
-1.7903030042984585,
|
||||
1.1028484616237284,
|
||||
1.731865132582606,
|
||||
-2.5926944354040096
|
||||
]
|
||||
},
|
||||
{
|
||||
"dc": -1.1502189348296572e-06,
|
||||
"amps": [
|
||||
0.0011732713800496743,
|
||||
8.715048457232978e-06,
|
||||
8.113829684732725e-06,
|
||||
2.805951507723943e-06,
|
||||
2.2956073119401994e-06
|
||||
],
|
||||
"freqs": [
|
||||
0.03333333333333333,
|
||||
0.02666666666666667,
|
||||
0.04,
|
||||
0.02,
|
||||
0.1
|
||||
],
|
||||
"phases": [
|
||||
-1.225940564415875,
|
||||
2.5874876850956996,
|
||||
-1.9715232735875732,
|
||||
-1.0313721340317885,
|
||||
-2.2437335289130216
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"dc": 0.004459296974043052,
|
||||
"amps": [
|
||||
4.365837863945567e-05,
|
||||
1.6627461404015874e-05,
|
||||
1.499327969764015e-05,
|
||||
1.0882240141500203e-05,
|
||||
8.648375991472251e-06
|
||||
],
|
||||
"freqs": [
|
||||
0.09333333333333334,
|
||||
0.1,
|
||||
0.13333333333333333,
|
||||
0.08666666666666667,
|
||||
0.10666666666666667
|
||||
],
|
||||
"phases": [
|
||||
-0.955645707880348,
|
||||
2.2853500968785534,
|
||||
0.39850354801733023,
|
||||
-0.6758960563529793,
|
||||
2.500473431154046
|
||||
]
|
||||
},
|
||||
{
|
||||
"dc": -9.51454075887644e-05,
|
||||
"amps": [
|
||||
0.0012646521264823782,
|
||||
0.00021337454745985233,
|
||||
0.00018204900807997863,
|
||||
0.0001045493570771146,
|
||||
9.486869355170616e-05
|
||||
],
|
||||
"freqs": [
|
||||
0.04666666666666667,
|
||||
0.05333333333333334,
|
||||
0.04,
|
||||
0.03333333333333333,
|
||||
0.060000000000000005
|
||||
],
|
||||
"phases": [
|
||||
3.0652144428661194,
|
||||
-0.07281059956203381,
|
||||
3.0763553688568286,
|
||||
3.0963827460231994,
|
||||
-0.08166873030294015
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"dc": 0.006754336698601643,
|
||||
"amps": [
|
||||
0.0001205644768172709,
|
||||
0.00010325204771730541,
|
||||
6.1032211125949833e-05,
|
||||
4.133092864305172e-05,
|
||||
3.322629507619568e-05
|
||||
],
|
||||
"freqs": [
|
||||
0.06666666666666667,
|
||||
0.07333333333333333,
|
||||
0.13333333333333333,
|
||||
0.060000000000000005,
|
||||
0.08
|
||||
],
|
||||
"phases": [
|
||||
0.21557592230485592,
|
||||
-2.886865293479548,
|
||||
-1.017309664173338,
|
||||
0.18116041037477737,
|
||||
-2.833486698409445
|
||||
]
|
||||
},
|
||||
{
|
||||
"dc": -0.00011794015166136282,
|
||||
"amps": [
|
||||
0.0027813392111168526,
|
||||
0.0008110970246664206,
|
||||
0.0005849442269674323,
|
||||
0.00035855985851303973,
|
||||
0.00033022754730012617
|
||||
],
|
||||
"freqs": [
|
||||
0.03333333333333333,
|
||||
0.04,
|
||||
0.02666666666666667,
|
||||
0.02,
|
||||
0.04666666666666667
|
||||
],
|
||||
"phases": [
|
||||
-2.728322858690305,
|
||||
0.49031498750676245,
|
||||
-2.808700524748656,
|
||||
-2.886553982431292,
|
||||
0.565211864386275
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"dc": 0.008447802712519964,
|
||||
"amps": [
|
||||
0.0002532245295392234,
|
||||
0.00014147298112950578,
|
||||
0.0001297400791941424,
|
||||
6.434300108105502e-05,
|
||||
5.7950849123282916e-05
|
||||
],
|
||||
"freqs": [
|
||||
0.08,
|
||||
0.07333333333333333,
|
||||
0.18000000000000002,
|
||||
0.08666666666666667,
|
||||
0.36000000000000004
|
||||
],
|
||||
"phases": [
|
||||
0.5998824737031915,
|
||||
-2.5827112781492545,
|
||||
-3.0945367379195816,
|
||||
0.6391142016853608,
|
||||
0.10751503340383528
|
||||
]
|
||||
},
|
||||
{
|
||||
"dc": 0.00011803933939518174,
|
||||
"amps": [
|
||||
0.004330276189305638,
|
||||
0.000976254738854663,
|
||||
0.0006186459734055383,
|
||||
0.0004722765324672463,
|
||||
0.000331904307497245
|
||||
],
|
||||
"freqs": [
|
||||
0.04,
|
||||
0.03333333333333333,
|
||||
0.04666666666666667,
|
||||
0.02666666666666667,
|
||||
0.02
|
||||
],
|
||||
"phases": [
|
||||
-2.551505303958517,
|
||||
0.5007165195151991,
|
||||
-2.466226000290465,
|
||||
0.4069960130268731,
|
||||
0.3090395499543929
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"dc": 0.005645164093002677,
|
||||
"amps": [
|
||||
9.94330093591307e-05,
|
||||
3.232916972111346e-05,
|
||||
1.3215355231141013e-05,
|
||||
1.1981542249045906e-05,
|
||||
1.1909839518599968e-05
|
||||
],
|
||||
"freqs": [
|
||||
0.08,
|
||||
0.13333333333333333,
|
||||
0.26666666666666666,
|
||||
0.2733333333333334,
|
||||
0.08666666666666667
|
||||
],
|
||||
"phases": [
|
||||
1.7159609635464452,
|
||||
-0.2507805590458965,
|
||||
1.0324605783803387,
|
||||
-1.6430097798845071,
|
||||
-1.2507241172270498
|
||||
]
|
||||
},
|
||||
{
|
||||
"dc": -7.872594342188676e-06,
|
||||
"amps": [
|
||||
0.0020951717499817367,
|
||||
0.00011698728994078175,
|
||||
9.559502592412231e-05,
|
||||
5.94451334704438e-05,
|
||||
4.6248624934531934e-05
|
||||
],
|
||||
"freqs": [
|
||||
0.04,
|
||||
0.04666666666666667,
|
||||
0.03333333333333333,
|
||||
0.05333333333333334,
|
||||
0.02666666666666667
|
||||
],
|
||||
"phases": [
|
||||
-1.9167863100531028,
|
||||
1.3060842750219288,
|
||||
-2.0155661953529633,
|
||||
1.3740336240558457,
|
||||
-2.1415896469819797
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"dc": 0.011301154401153327,
|
||||
"amps": [
|
||||
0.0005916813028667388,
|
||||
0.0003228542347087601,
|
||||
0.00011299686050540704,
|
||||
0.00010933004657394343,
|
||||
9.57751063779222e-05
|
||||
],
|
||||
"freqs": [
|
||||
0.060000000000000005,
|
||||
0.18000000000000002,
|
||||
0.35333333333333333,
|
||||
0.06666666666666667,
|
||||
0.36000000000000004
|
||||
],
|
||||
"phases": [
|
||||
-1.2029089114719096,
|
||||
0.10667750417539099,
|
||||
0.8128110625734376,
|
||||
1.9355161635025424,
|
||||
-1.7526560628277699
|
||||
]
|
||||
},
|
||||
{
|
||||
"dc": 0.000209219001474897,
|
||||
"amps": [
|
||||
0.00560199847829251,
|
||||
0.0038799719967085497,
|
||||
0.0017754993231967535,
|
||||
0.0012951582037757647,
|
||||
0.001094199761464694
|
||||
],
|
||||
"freqs": [
|
||||
0.03333333333333333,
|
||||
0.02666666666666667,
|
||||
0.04,
|
||||
0.02,
|
||||
0.04666666666666667
|
||||
],
|
||||
"phases": [
|
||||
-1.8630748640530403,
|
||||
1.1749393426220804,
|
||||
-1.7802277933394777,
|
||||
1.028375164210408,
|
||||
-1.7139048570401034
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"force_norm_fact": 1.0,
|
||||
"sens_deviation": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"sens_norm_fact": [
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
1.0
|
||||
],
|
||||
"action_bias": [
|
||||
0.0,
|
||||
-5.1,
|
||||
5.1
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"scene": "steady",
|
||||
"controlled": true,
|
||||
"source": "open_loop",
|
||||
"action_constant": [
|
||||
0.0,
|
||||
-0.051,
|
||||
0.051
|
||||
],
|
||||
"note": "open-loop constant rotation, no PPO model"
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"scene": "karman_re100",
|
||||
"channels": [
|
||||
{
|
||||
"channel": "front",
|
||||
"best_r2": 0.9950013415086292,
|
||||
"best_nz": 21,
|
||||
"pareto": [
|
||||
{
|
||||
"nz": 2,
|
||||
"r2": 0.8681678005649112
|
||||
},
|
||||
{
|
||||
"nz": 3,
|
||||
"r2": 0.9692414821446799
|
||||
},
|
||||
{
|
||||
"nz": 4,
|
||||
"r2": 0.989378747581318
|
||||
},
|
||||
{
|
||||
"nz": 6,
|
||||
"r2": 0.9908017426802015
|
||||
},
|
||||
{
|
||||
"nz": 12,
|
||||
"r2": 0.9939890287801123
|
||||
},
|
||||
{
|
||||
"nz": 13,
|
||||
"r2": 0.9947660566975605
|
||||
},
|
||||
{
|
||||
"nz": 18,
|
||||
"r2": 0.9949963098276752
|
||||
},
|
||||
{
|
||||
"nz": 21,
|
||||
"r2": 0.9950013415086292
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"channel": "top",
|
||||
"best_r2": 0.9928439394510484,
|
||||
"best_nz": 22,
|
||||
"pareto": [
|
||||
{
|
||||
"nz": 1,
|
||||
"r2": 0.44188145385324007
|
||||
},
|
||||
{
|
||||
"nz": 2,
|
||||
"r2": 0.9285296099294669
|
||||
},
|
||||
{
|
||||
"nz": 6,
|
||||
"r2": 0.9812946866555053
|
||||
},
|
||||
{
|
||||
"nz": 12,
|
||||
"r2": 0.9909377708950154
|
||||
},
|
||||
{
|
||||
"nz": 17,
|
||||
"r2": 0.9927843560231949
|
||||
},
|
||||
{
|
||||
"nz": 20,
|
||||
"r2": 0.992824536423302
|
||||
},
|
||||
{
|
||||
"nz": 22,
|
||||
"r2": 0.9928439394510484
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"channel": "bottom",
|
||||
"best_r2": 0.9965335484991993,
|
||||
"best_nz": 22,
|
||||
"pareto": [
|
||||
{
|
||||
"nz": 1,
|
||||
"r2": 0.8456588970543057
|
||||
},
|
||||
{
|
||||
"nz": 2,
|
||||
"r2": 0.9030386794798415
|
||||
},
|
||||
{
|
||||
"nz": 8,
|
||||
"r2": 0.9947803148283133
|
||||
},
|
||||
{
|
||||
"nz": 10,
|
||||
"r2": 0.9962551509064745
|
||||
},
|
||||
{
|
||||
"nz": 13,
|
||||
"r2": 0.9963877299663628
|
||||
},
|
||||
{
|
||||
"nz": 16,
|
||||
"r2": 0.9964335809851655
|
||||
},
|
||||
{
|
||||
"nz": 18,
|
||||
"r2": 0.9965311727162228
|
||||
},
|
||||
{
|
||||
"nz": 22,
|
||||
"r2": 0.9965335484991993
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
{
|
||||
"scene": "vortex_lamb",
|
||||
"channels": [
|
||||
{
|
||||
"channel": "front",
|
||||
"best_r2": 0.9035051679446613,
|
||||
"best_nz": 21,
|
||||
"pareto": [
|
||||
{
|
||||
"nz": 3,
|
||||
"r2": 0.8536388609680176
|
||||
},
|
||||
{
|
||||
"nz": 8,
|
||||
"r2": 0.8957625139671737
|
||||
},
|
||||
{
|
||||
"nz": 9,
|
||||
"r2": 0.8985847902462778
|
||||
},
|
||||
{
|
||||
"nz": 16,
|
||||
"r2": 0.9017891237504362
|
||||
},
|
||||
{
|
||||
"nz": 20,
|
||||
"r2": 0.9035028044287374
|
||||
},
|
||||
{
|
||||
"nz": 21,
|
||||
"r2": 0.9035051679446613
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"channel": "top",
|
||||
"best_r2": 0.979810012198325,
|
||||
"best_nz": 22,
|
||||
"pareto": [
|
||||
{
|
||||
"nz": 0,
|
||||
"r2": -0.2926478447353347
|
||||
},
|
||||
{
|
||||
"nz": 1,
|
||||
"r2": 0.9262664550660489
|
||||
},
|
||||
{
|
||||
"nz": 2,
|
||||
"r2": 0.9602153300731789
|
||||
},
|
||||
{
|
||||
"nz": 5,
|
||||
"r2": 0.9685659511773673
|
||||
},
|
||||
{
|
||||
"nz": 6,
|
||||
"r2": 0.9752589669369754
|
||||
},
|
||||
{
|
||||
"nz": 19,
|
||||
"r2": 0.9796029724451923
|
||||
},
|
||||
{
|
||||
"nz": 20,
|
||||
"r2": 0.9797408009698567
|
||||
},
|
||||
{
|
||||
"nz": 22,
|
||||
"r2": 0.979810012198325
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"channel": "bottom",
|
||||
"best_r2": 0.9334422885170565,
|
||||
"best_nz": 22,
|
||||
"pareto": [
|
||||
{
|
||||
"nz": 0,
|
||||
"r2": -5.4349952892154265
|
||||
},
|
||||
{
|
||||
"nz": 1,
|
||||
"r2": 0.6935730348615337
|
||||
},
|
||||
{
|
||||
"nz": 5,
|
||||
"r2": 0.8721441125489685
|
||||
},
|
||||
{
|
||||
"nz": 7,
|
||||
"r2": 0.8963211646824344
|
||||
},
|
||||
{
|
||||
"nz": 11,
|
||||
"r2": 0.9294742132351927
|
||||
},
|
||||
{
|
||||
"nz": 15,
|
||||
"r2": 0.9318911728011019
|
||||
},
|
||||
{
|
||||
"nz": 22,
|
||||
"r2": 0.9334422885170565
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"scene": "vortex_taylor",
|
||||
"channels": [
|
||||
{
|
||||
"channel": "front",
|
||||
"best_r2": 0.9603622630700551,
|
||||
"best_nz": 21,
|
||||
"pareto": [
|
||||
{
|
||||
"nz": 0,
|
||||
"r2": -1762.7026716770156
|
||||
},
|
||||
{
|
||||
"nz": 21,
|
||||
"r2": 0.9603622630700551
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"channel": "top",
|
||||
"best_r2": 0.809824114603052,
|
||||
"best_nz": 22,
|
||||
"pareto": [
|
||||
{
|
||||
"nz": 0,
|
||||
"r2": -3813.3981416722418
|
||||
},
|
||||
{
|
||||
"nz": 1,
|
||||
"r2": 4.909409545561516e-09
|
||||
},
|
||||
{
|
||||
"nz": 22,
|
||||
"r2": 0.809824114603052
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"channel": "bottom",
|
||||
"best_r2": 0.6431303693566448,
|
||||
"best_nz": 22,
|
||||
"pareto": [
|
||||
{
|
||||
"nz": 0,
|
||||
"r2": -11389.175969107222
|
||||
},
|
||||
{
|
||||
"nz": 1,
|
||||
"r2": 2.5346330034814457e-08
|
||||
},
|
||||
{
|
||||
"nz": 22,
|
||||
"r2": 0.6431303693566448
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 140 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 152 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 151 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 148 KiB |
@@ -0,0 +1,210 @@
|
||||
{
|
||||
"karman_re100_front": {
|
||||
"output_label": "karman_re100_front",
|
||||
"n_samples": 198,
|
||||
"n_features": 1,
|
||||
"feature_names": [
|
||||
"aF_lag1"
|
||||
],
|
||||
"niterations": 50,
|
||||
"best_equation": "(x0 * 0.01106541) / 1.106541",
|
||||
"best_loss": 1.4959569e-19,
|
||||
"r2": 1.0,
|
||||
"equations": [
|
||||
{
|
||||
"complexity": 1,
|
||||
"loss": 0.00018302062,
|
||||
"score": 0.0,
|
||||
"equation": "-0.003915151",
|
||||
"sympy_format": "-0.00391515100000000"
|
||||
},
|
||||
{
|
||||
"complexity": 3,
|
||||
"loss": 1.7232441999999998e-19,
|
||||
"score": 17.299498177983697,
|
||||
"equation": "x0 * 0.01",
|
||||
"sympy_format": "x0*0.01"
|
||||
},
|
||||
{
|
||||
"complexity": 5,
|
||||
"loss": 1.4959569e-19,
|
||||
"score": 0.07072130403388514,
|
||||
"equation": "(x0 * 0.01106541) / 1.106541",
|
||||
"sympy_format": "x0*0.01106541/1.106541"
|
||||
}
|
||||
]
|
||||
},
|
||||
"karman_re100_top": {
|
||||
"output_label": "karman_re100_top",
|
||||
"n_samples": 198,
|
||||
"n_features": 7,
|
||||
"feature_names": [
|
||||
"bias",
|
||||
"u_a",
|
||||
"Cd_rear",
|
||||
"Cl_diff",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1"
|
||||
],
|
||||
"niterations": 50,
|
||||
"best_equation": "(x6 * -0.00835853) / -0.835853",
|
||||
"best_loss": 2.8386383999999997e-18,
|
||||
"r2": 1.0,
|
||||
"equations": [
|
||||
{
|
||||
"complexity": 1,
|
||||
"loss": 0.00031669735,
|
||||
"score": 0.0,
|
||||
"equation": "0.041159406",
|
||||
"sympy_format": "0.0411594060000000"
|
||||
},
|
||||
{
|
||||
"complexity": 3,
|
||||
"loss": 3.732284e-18,
|
||||
"score": 16.035973661600742,
|
||||
"equation": "x6 * 0.01",
|
||||
"sympy_format": "x6*0.01"
|
||||
},
|
||||
{
|
||||
"complexity": 5,
|
||||
"loss": 2.8386383999999997e-18,
|
||||
"score": 0.13684793905473897,
|
||||
"equation": "(x6 * -0.00835853) / -0.835853",
|
||||
"sympy_format": "x6*(-0.00835853)/(-0.835853)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"illusion_1L_front": {
|
||||
"output_label": "illusion_1L_front",
|
||||
"n_samples": 198,
|
||||
"n_features": 14,
|
||||
"feature_names": [
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT"
|
||||
],
|
||||
"niterations": 100,
|
||||
"best_equation": "((0.0039467034 * (x8 + x8)) - ((x8 / (-0.9984451 - (x4 + x8))) * square(2.5222103e-6))) / 0.7893407",
|
||||
"best_loss": 8.728418e-19,
|
||||
"r2": 1.0,
|
||||
"equations": [
|
||||
{
|
||||
"complexity": 1,
|
||||
"loss": 0.004748166,
|
||||
"score": 0.0,
|
||||
"equation": "0.0012775909",
|
||||
"sympy_format": "0.00127759090000000"
|
||||
},
|
||||
{
|
||||
"complexity": 3,
|
||||
"loss": 2.6305633999999998e-18,
|
||||
"score": 17.564668394678097,
|
||||
"equation": "x8 * 0.01",
|
||||
"sympy_format": "x8*0.01"
|
||||
},
|
||||
{
|
||||
"complexity": 5,
|
||||
"loss": 1.3032371999999998e-18,
|
||||
"score": 0.35117336038102565,
|
||||
"equation": "(0.007208903 * x8) / 0.7208903",
|
||||
"sympy_format": "0.007208903*x8/0.7208903"
|
||||
},
|
||||
{
|
||||
"complexity": 7,
|
||||
"loss": 1.1532010999999999e-18,
|
||||
"score": 0.06115484118442259,
|
||||
"equation": "((x8 + x8) * 0.0039467034) / 0.7893407",
|
||||
"sympy_format": "(x8 + x8)*0.0039467034/0.7893407"
|
||||
},
|
||||
{
|
||||
"complexity": 9,
|
||||
"loss": 1.1488888999999999e-18,
|
||||
"score": 0.001873169616955362,
|
||||
"equation": "(((x8 + x8) - 1.3038937e-7) * 0.0039467034) / 0.7893407",
|
||||
"sympy_format": "(x8 + x8 - 1*1.3038937e-7)*0.0039467034/0.7893407"
|
||||
},
|
||||
{
|
||||
"complexity": 12,
|
||||
"loss": 1.1395758999999998e-18,
|
||||
"score": 0.0027130419227974806,
|
||||
"equation": "(((x8 + x8) * 0.0039467034) - square(x7 * -3.0155393e-6)) / 0.7893407",
|
||||
"sympy_format": "(-9.09347726984449e-12*x7**2 + (x8 + x8)*0.0039467034)/0.7893407"
|
||||
},
|
||||
{
|
||||
"complexity": 14,
|
||||
"loss": 1.0790729e-18,
|
||||
"score": 0.02727696454758814,
|
||||
"equation": "((x8 + (x8 - square((x13 + x13) * -1.5024679e-5))) * 0.0039467034) / 0.7893407",
|
||||
"sympy_format": "(x8 + x8 - 2.25740979053041e-10*(x13 + x13)**2)*0.0039467034/0.7893407"
|
||||
},
|
||||
{
|
||||
"complexity": 18,
|
||||
"loss": 8.728418e-19,
|
||||
"score": 0.05302580007984551,
|
||||
"equation": "((0.0039467034 * (x8 + x8)) - ((x8 / (-0.9984451 - (x4 + x8))) * square(2.5222103e-6))) / 0.7893407",
|
||||
"sympy_format": "(-6.36154479742609e-12*x8/(-(x4 + x8) - 0.9984451) + 0.0039467034*(x8 + x8))/0.7893407"
|
||||
}
|
||||
]
|
||||
},
|
||||
"illusion_1L_top": {
|
||||
"output_label": "illusion_1L_top",
|
||||
"n_samples": 198,
|
||||
"n_features": 15,
|
||||
"feature_names": [
|
||||
"bias",
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT"
|
||||
],
|
||||
"niterations": 100,
|
||||
"best_equation": "(x11 * 0.0121531105) / 1.215311",
|
||||
"best_loss": 2.9856626999999997e-18,
|
||||
"r2": 1.0,
|
||||
"equations": [
|
||||
{
|
||||
"complexity": 1,
|
||||
"loss": 0.0034831127,
|
||||
"score": 0.0,
|
||||
"equation": "0.01056136",
|
||||
"sympy_format": "0.0105613600000000"
|
||||
},
|
||||
{
|
||||
"complexity": 3,
|
||||
"loss": 3.6416598e-18,
|
||||
"score": 17.247131588103095,
|
||||
"equation": "x11 * 0.01",
|
||||
"sympy_format": "x11*0.01"
|
||||
},
|
||||
{
|
||||
"complexity": 5,
|
||||
"loss": 2.9856626999999997e-18,
|
||||
"score": 0.09930891723700508,
|
||||
"equation": "(x11 * 0.0121531105) / 1.215311",
|
||||
"sympy_format": "x11*0.0121531105/1.215311"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,618 @@
|
||||
{
|
||||
"thresholds": [
|
||||
0.0,
|
||||
0.001,
|
||||
0.002,
|
||||
0.005,
|
||||
0.01,
|
||||
0.015,
|
||||
0.02,
|
||||
0.03,
|
||||
0.05,
|
||||
0.1
|
||||
],
|
||||
"feature_names_front": [
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT",
|
||||
"mu",
|
||||
"mu_u_a",
|
||||
"mu_v_a",
|
||||
"mu_Cd_tot",
|
||||
"mu_Cl_diff"
|
||||
],
|
||||
"feature_names_rear": [
|
||||
"bias",
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT",
|
||||
"mu",
|
||||
"mu_u_a",
|
||||
"mu_v_a",
|
||||
"mu_Cd_tot",
|
||||
"mu_Cl_diff"
|
||||
],
|
||||
"per_scene": {
|
||||
"karman_re100": {
|
||||
"scene": "karman_re100",
|
||||
"re_code": 100,
|
||||
"mu": 0.02,
|
||||
"feature_names_front": [
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT",
|
||||
"mu",
|
||||
"mu_u_a",
|
||||
"mu_v_a",
|
||||
"mu_Cd_tot",
|
||||
"mu_Cl_diff"
|
||||
],
|
||||
"feature_names_rear": [
|
||||
"bias",
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT",
|
||||
"mu",
|
||||
"mu_u_a",
|
||||
"mu_v_a",
|
||||
"mu_Cd_tot",
|
||||
"mu_Cl_diff"
|
||||
],
|
||||
"front": {
|
||||
"results": [
|
||||
{
|
||||
"threshold": 0.0,
|
||||
"nz": 21,
|
||||
"r2": 0.9963468671522658,
|
||||
"mae": 0.008495019589563084,
|
||||
"weights_min": 0.2538872797382758,
|
||||
"weights_max": 1.0371907088754313
|
||||
},
|
||||
{
|
||||
"threshold": 0.001,
|
||||
"nz": 18,
|
||||
"r2": 0.9963454010383349,
|
||||
"mae": 0.008500938429721638,
|
||||
"weights_min": 0.2538872797382758,
|
||||
"weights_max": 1.0371907088754313
|
||||
},
|
||||
{
|
||||
"threshold": 0.002,
|
||||
"nz": 18,
|
||||
"r2": 0.9963454010383349,
|
||||
"mae": 0.008500938429721638,
|
||||
"weights_min": 0.2538872797382758,
|
||||
"weights_max": 1.0371907088754313
|
||||
},
|
||||
{
|
||||
"threshold": 0.005,
|
||||
"nz": 12,
|
||||
"r2": 0.9947081910813219,
|
||||
"mae": 0.010856555791902431,
|
||||
"weights_min": 0.2538872797382758,
|
||||
"weights_max": 1.0371907088754313
|
||||
},
|
||||
{
|
||||
"threshold": 0.01,
|
||||
"nz": 9,
|
||||
"r2": 0.9944015269767014,
|
||||
"mae": 0.010728158860757616,
|
||||
"weights_min": 0.2538872797382758,
|
||||
"weights_max": 1.0371907088754313
|
||||
},
|
||||
{
|
||||
"threshold": 0.015,
|
||||
"nz": 4,
|
||||
"r2": 0.9805810563712329,
|
||||
"mae": 0.02109193834223528,
|
||||
"weights_min": 0.2538872797382758,
|
||||
"weights_max": 1.0371907088754313
|
||||
},
|
||||
{
|
||||
"threshold": 0.02,
|
||||
"nz": 3,
|
||||
"r2": 0.969677527911751,
|
||||
"mae": 0.024398378538262957,
|
||||
"weights_min": 0.2538872797382758,
|
||||
"weights_max": 1.0371907088754313
|
||||
},
|
||||
{
|
||||
"threshold": 0.03,
|
||||
"nz": 3,
|
||||
"r2": 0.969677527911751,
|
||||
"mae": 0.024398378538262957,
|
||||
"weights_min": 0.2538872797382758,
|
||||
"weights_max": 1.0371907088754313
|
||||
},
|
||||
{
|
||||
"threshold": 0.05,
|
||||
"nz": 3,
|
||||
"r2": 0.969677527911751,
|
||||
"mae": 0.024398378538262957,
|
||||
"weights_min": 0.2538872797382758,
|
||||
"weights_max": 1.0371907088754313
|
||||
},
|
||||
{
|
||||
"threshold": 0.1,
|
||||
"nz": 2,
|
||||
"r2": 0.8671246137520265,
|
||||
"mae": 0.0536574860231316,
|
||||
"weights_min": 0.2538872797382758,
|
||||
"weights_max": 1.0371907088754313
|
||||
}
|
||||
],
|
||||
"best": {
|
||||
"threshold": 0.002,
|
||||
"nz": 18,
|
||||
"r2": 0.9963454010383349,
|
||||
"mae": 0.008500938429721638,
|
||||
"weights_min": 0.2538872797382758,
|
||||
"weights_max": 1.0371907088754313
|
||||
},
|
||||
"best_coef": [
|
||||
0.003380802864171953,
|
||||
-0.0008809022653997198,
|
||||
0.0,
|
||||
0.00208717851683782,
|
||||
0.009307953320832238,
|
||||
0.012225442968436223,
|
||||
-0.007383343207562919,
|
||||
0.019594876551595624,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0071310792485739126,
|
||||
0.0014536838339802387,
|
||||
-0.004129923355485657,
|
||||
0.0014498851666906254,
|
||||
-0.0027671395780320186,
|
||||
0.0021240428248806,
|
||||
0.9081582144711916,
|
||||
-0.044045113030994884,
|
||||
0.10435892480150129,
|
||||
0.4653976700088291,
|
||||
0.979743839707262
|
||||
],
|
||||
"sparsity_curve": [
|
||||
[
|
||||
0.0,
|
||||
21,
|
||||
0.9963468671522658
|
||||
],
|
||||
[
|
||||
0.001,
|
||||
18,
|
||||
0.9963454010383349
|
||||
],
|
||||
[
|
||||
0.002,
|
||||
18,
|
||||
0.9963454010383349
|
||||
],
|
||||
[
|
||||
0.005,
|
||||
12,
|
||||
0.9947081910813219
|
||||
],
|
||||
[
|
||||
0.01,
|
||||
9,
|
||||
0.9944015269767014
|
||||
],
|
||||
[
|
||||
0.015,
|
||||
4,
|
||||
0.9805810563712329
|
||||
],
|
||||
[
|
||||
0.02,
|
||||
3,
|
||||
0.969677527911751
|
||||
],
|
||||
[
|
||||
0.03,
|
||||
3,
|
||||
0.969677527911751
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
3,
|
||||
0.969677527911751
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
2,
|
||||
0.8671246137520265
|
||||
]
|
||||
]
|
||||
},
|
||||
"top": {
|
||||
"results": [
|
||||
{
|
||||
"threshold": 0.0,
|
||||
"nz": 22,
|
||||
"r2": 0.9947943202493076,
|
||||
"mae": 0.013882836661429927,
|
||||
"weights_min": 0.36423882973791505,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.001,
|
||||
"nz": 20,
|
||||
"r2": 0.9947724287185891,
|
||||
"mae": 0.013998132434573892,
|
||||
"weights_min": 0.36423882973791505,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.002,
|
||||
"nz": 18,
|
||||
"r2": 0.9947437375025526,
|
||||
"mae": 0.013973729698665602,
|
||||
"weights_min": 0.36423882973791505,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.005,
|
||||
"nz": 18,
|
||||
"r2": 0.9947437375025526,
|
||||
"mae": 0.013973729698665602,
|
||||
"weights_min": 0.36423882973791505,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.01,
|
||||
"nz": 12,
|
||||
"r2": 0.9930561323691804,
|
||||
"mae": 0.015350435484475112,
|
||||
"weights_min": 0.36423882973791505,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.015,
|
||||
"nz": 12,
|
||||
"r2": 0.9930561323691804,
|
||||
"mae": 0.015350435484475112,
|
||||
"weights_min": 0.36423882973791505,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.02,
|
||||
"nz": 12,
|
||||
"r2": 0.9930561323691804,
|
||||
"mae": 0.015350435484475112,
|
||||
"weights_min": 0.36423882973791505,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.03,
|
||||
"nz": 6,
|
||||
"r2": 0.9829012294927744,
|
||||
"mae": 0.024013187353778373,
|
||||
"weights_min": 0.36423882973791505,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.05,
|
||||
"nz": 2,
|
||||
"r2": 0.9310887280966665,
|
||||
"mae": 0.04519335614359589,
|
||||
"weights_min": 0.36423882973791505,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.1,
|
||||
"nz": 1,
|
||||
"r2": 0.42576849886018275,
|
||||
"mae": 0.12579383759812146,
|
||||
"weights_min": 0.36423882973791505,
|
||||
"weights_max": 1.1067365435175973
|
||||
}
|
||||
],
|
||||
"best": {
|
||||
"threshold": 0.002,
|
||||
"nz": 18,
|
||||
"r2": 0.9947437375025526,
|
||||
"mae": 0.013973729698665602,
|
||||
"weights_min": 0.36423882973791505,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
"best_coef": [
|
||||
0.9115729610071152,
|
||||
-0.006805683305581021,
|
||||
-0.00407714864334097,
|
||||
0.0028603164071186993,
|
||||
0.0,
|
||||
-0.020649798768545318,
|
||||
0.033591198632074694,
|
||||
0.09195198469780816,
|
||||
0.0232186348784368,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0035421651717378612,
|
||||
0.009890204105631987,
|
||||
0.0028849152878799955,
|
||||
-0.000946773567394545,
|
||||
-0.00391306181767762,
|
||||
0.005116314559440586,
|
||||
0.018231459167452172,
|
||||
-0.20385743262256592,
|
||||
0.0,
|
||||
-1.0324899193623733,
|
||||
1.1609316346427214
|
||||
],
|
||||
"sparsity_curve": [
|
||||
[
|
||||
0.0,
|
||||
22,
|
||||
0.9947943202493076
|
||||
],
|
||||
[
|
||||
0.001,
|
||||
20,
|
||||
0.9947724287185891
|
||||
],
|
||||
[
|
||||
0.002,
|
||||
18,
|
||||
0.9947437375025526
|
||||
],
|
||||
[
|
||||
0.005,
|
||||
18,
|
||||
0.9947437375025526
|
||||
],
|
||||
[
|
||||
0.01,
|
||||
12,
|
||||
0.9930561323691804
|
||||
],
|
||||
[
|
||||
0.015,
|
||||
12,
|
||||
0.9930561323691804
|
||||
],
|
||||
[
|
||||
0.02,
|
||||
12,
|
||||
0.9930561323691804
|
||||
],
|
||||
[
|
||||
0.03,
|
||||
6,
|
||||
0.9829012294927744
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
2,
|
||||
0.9310887280966665
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
1,
|
||||
0.42576849886018275
|
||||
]
|
||||
]
|
||||
},
|
||||
"bottom": {
|
||||
"results": [
|
||||
{
|
||||
"threshold": 0.0,
|
||||
"nz": 22,
|
||||
"r2": 0.9974702578481651,
|
||||
"mae": 0.011121305785433843,
|
||||
"weights_min": 0.2863478575619962,
|
||||
"weights_max": 1.0399071561860243
|
||||
},
|
||||
{
|
||||
"threshold": 0.001,
|
||||
"nz": 18,
|
||||
"r2": 0.9974635520604825,
|
||||
"mae": 0.011155185750820898,
|
||||
"weights_min": 0.2863478575619962,
|
||||
"weights_max": 1.0399071561860243
|
||||
},
|
||||
{
|
||||
"threshold": 0.002,
|
||||
"nz": 16,
|
||||
"r2": 0.9974006411842374,
|
||||
"mae": 0.011251386324348665,
|
||||
"weights_min": 0.2863478575619962,
|
||||
"weights_max": 1.0399071561860243
|
||||
},
|
||||
{
|
||||
"threshold": 0.005,
|
||||
"nz": 16,
|
||||
"r2": 0.9974006411842374,
|
||||
"mae": 0.011251386324348665,
|
||||
"weights_min": 0.2863478575619962,
|
||||
"weights_max": 1.0399071561860243
|
||||
},
|
||||
{
|
||||
"threshold": 0.01,
|
||||
"nz": 10,
|
||||
"r2": 0.9971310266820465,
|
||||
"mae": 0.011717975996893105,
|
||||
"weights_min": 0.2863478575619962,
|
||||
"weights_max": 1.0399071561860243
|
||||
},
|
||||
{
|
||||
"threshold": 0.015,
|
||||
"nz": 8,
|
||||
"r2": 0.9955140894896422,
|
||||
"mae": 0.01509793962669375,
|
||||
"weights_min": 0.2863478575619962,
|
||||
"weights_max": 1.0399071561860243
|
||||
},
|
||||
{
|
||||
"threshold": 0.02,
|
||||
"nz": 8,
|
||||
"r2": 0.9955140894896422,
|
||||
"mae": 0.01509793962669375,
|
||||
"weights_min": 0.2863478575619962,
|
||||
"weights_max": 1.0399071561860243
|
||||
},
|
||||
{
|
||||
"threshold": 0.03,
|
||||
"nz": 5,
|
||||
"r2": 0.9920045223882177,
|
||||
"mae": 0.01968881107737399,
|
||||
"weights_min": 0.2863478575619962,
|
||||
"weights_max": 1.0399071561860243
|
||||
},
|
||||
{
|
||||
"threshold": 0.05,
|
||||
"nz": 2,
|
||||
"r2": 0.9027764309517692,
|
||||
"mae": 0.06593190744450401,
|
||||
"weights_min": 0.2863478575619962,
|
||||
"weights_max": 1.0399071561860243
|
||||
},
|
||||
{
|
||||
"threshold": 0.1,
|
||||
"nz": 1,
|
||||
"r2": 0.8435989700357883,
|
||||
"mae": 0.08688057754133625,
|
||||
"weights_min": 0.2863478575619962,
|
||||
"weights_max": 1.0399071561860243
|
||||
}
|
||||
],
|
||||
"best": {
|
||||
"threshold": 0.002,
|
||||
"nz": 16,
|
||||
"r2": 0.9974006411842374,
|
||||
"mae": 0.011251386324348665,
|
||||
"weights_min": 0.2863478575619962,
|
||||
"weights_max": 1.0399071561860243
|
||||
},
|
||||
"best_coef": [
|
||||
-0.3062392108066253,
|
||||
0.005083824376570689,
|
||||
-0.0019100164756928636,
|
||||
-0.0032417665760502293,
|
||||
0.0,
|
||||
0.0,
|
||||
-0.016413610065012466,
|
||||
0.062146484641493534,
|
||||
-0.005222530364610314,
|
||||
0.0,
|
||||
0.0,
|
||||
0.003517044018032268,
|
||||
0.00988827788555667,
|
||||
0.0023305542256132016,
|
||||
-0.0015468136369196132,
|
||||
0.004824491806330017,
|
||||
-0.0032570158106502616,
|
||||
-0.00612478415924937,
|
||||
-0.09550082351895658,
|
||||
0.0,
|
||||
0.0,
|
||||
-0.26112655898206505
|
||||
],
|
||||
"sparsity_curve": [
|
||||
[
|
||||
0.0,
|
||||
22,
|
||||
0.9974702578481651
|
||||
],
|
||||
[
|
||||
0.001,
|
||||
18,
|
||||
0.9974635520604825
|
||||
],
|
||||
[
|
||||
0.002,
|
||||
16,
|
||||
0.9974006411842374
|
||||
],
|
||||
[
|
||||
0.005,
|
||||
16,
|
||||
0.9974006411842374
|
||||
],
|
||||
[
|
||||
0.01,
|
||||
10,
|
||||
0.9971310266820465
|
||||
],
|
||||
[
|
||||
0.015,
|
||||
8,
|
||||
0.9955140894896422
|
||||
],
|
||||
[
|
||||
0.02,
|
||||
8,
|
||||
0.9955140894896422
|
||||
],
|
||||
[
|
||||
0.03,
|
||||
5,
|
||||
0.9920045223882177
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
2,
|
||||
0.9027764309517692
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
1,
|
||||
0.8435989700357883
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
{
|
||||
"thresholds": [
|
||||
0.0,
|
||||
0.001,
|
||||
0.002,
|
||||
0.005,
|
||||
0.01,
|
||||
0.015,
|
||||
0.02,
|
||||
0.03,
|
||||
0.05,
|
||||
0.1
|
||||
],
|
||||
"feature_names_front": [
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT"
|
||||
],
|
||||
"feature_names_rear": [
|
||||
"bias",
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT"
|
||||
],
|
||||
"per_scene": {
|
||||
"karman_re100": {
|
||||
"scene": "karman_re100",
|
||||
"re_code": 100,
|
||||
"mu": 0.02,
|
||||
"feature_names_front": [
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT"
|
||||
],
|
||||
"feature_names_rear": [
|
||||
"bias",
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT"
|
||||
],
|
||||
"front": {
|
||||
"results": [
|
||||
{
|
||||
"threshold": 0.0,
|
||||
"nz": 16,
|
||||
"r2": 0.9964173297164212,
|
||||
"mae": 0.008496979102955536,
|
||||
"weights_min": 0.2778368062626606,
|
||||
"weights_max": 1.037970618101812
|
||||
},
|
||||
{
|
||||
"threshold": 0.001,
|
||||
"nz": 13,
|
||||
"r2": 0.9964170471154649,
|
||||
"mae": 0.00849877674299794,
|
||||
"weights_min": 0.2778368062626606,
|
||||
"weights_max": 1.037970618101812
|
||||
},
|
||||
{
|
||||
"threshold": 0.002,
|
||||
"nz": 13,
|
||||
"r2": 0.9964170471154649,
|
||||
"mae": 0.00849877674299794,
|
||||
"weights_min": 0.2778368062626606,
|
||||
"weights_max": 1.037970618101812
|
||||
},
|
||||
{
|
||||
"threshold": 0.005,
|
||||
"nz": 3,
|
||||
"r2": 0.9885903068210383,
|
||||
"mae": 0.014540007299834038,
|
||||
"weights_min": 0.2778368062626606,
|
||||
"weights_max": 1.037970618101812
|
||||
},
|
||||
{
|
||||
"threshold": 0.01,
|
||||
"nz": 3,
|
||||
"r2": 0.9801597431201753,
|
||||
"mae": 0.02107344007147761,
|
||||
"weights_min": 0.2778368062626606,
|
||||
"weights_max": 1.037970618101812
|
||||
},
|
||||
{
|
||||
"threshold": 0.015,
|
||||
"nz": 3,
|
||||
"r2": 0.9801597431201753,
|
||||
"mae": 0.02107344007147761,
|
||||
"weights_min": 0.2778368062626606,
|
||||
"weights_max": 1.037970618101812
|
||||
},
|
||||
{
|
||||
"threshold": 0.02,
|
||||
"nz": 2,
|
||||
"r2": 0.9680925119257522,
|
||||
"mae": 0.024303837665639722,
|
||||
"weights_min": 0.2778368062626606,
|
||||
"weights_max": 1.037970618101812
|
||||
},
|
||||
{
|
||||
"threshold": 0.03,
|
||||
"nz": 2,
|
||||
"r2": 0.9680925119257522,
|
||||
"mae": 0.024303837665639722,
|
||||
"weights_min": 0.2778368062626606,
|
||||
"weights_max": 1.037970618101812
|
||||
},
|
||||
{
|
||||
"threshold": 0.05,
|
||||
"nz": 2,
|
||||
"r2": 0.9680925119257522,
|
||||
"mae": 0.024303837665639722,
|
||||
"weights_min": 0.2778368062626606,
|
||||
"weights_max": 1.037970618101812
|
||||
},
|
||||
{
|
||||
"threshold": 0.1,
|
||||
"nz": 1,
|
||||
"r2": 0.8667444738394041,
|
||||
"mae": 0.053551706949699907,
|
||||
"weights_min": 0.2778368062626606,
|
||||
"weights_max": 1.037970618101812
|
||||
}
|
||||
],
|
||||
"best": {
|
||||
"threshold": 0.002,
|
||||
"nz": 13,
|
||||
"r2": 0.9964170471154649,
|
||||
"mae": 0.00849877674299794,
|
||||
"weights_min": 0.2778368062626606,
|
||||
"weights_max": 1.037970618101812
|
||||
},
|
||||
"best_coef": [
|
||||
0.0035693198413540234,
|
||||
-0.0018962945486085396,
|
||||
0.0,
|
||||
0.004246223224503542,
|
||||
0.01867909228324871,
|
||||
0.011809790151579671,
|
||||
-0.006291860766813562,
|
||||
0.03938466562589553,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0071131542686216345,
|
||||
0.0015118413457375216,
|
||||
-0.004145051172507872,
|
||||
0.0014265611111992293,
|
||||
-0.0028705905475650928,
|
||||
0.0021914873908442335
|
||||
],
|
||||
"sparsity_curve": [
|
||||
[
|
||||
0.0,
|
||||
16,
|
||||
0.9964173297164212
|
||||
],
|
||||
[
|
||||
0.001,
|
||||
13,
|
||||
0.9964170471154649
|
||||
],
|
||||
[
|
||||
0.002,
|
||||
13,
|
||||
0.9964170471154649
|
||||
],
|
||||
[
|
||||
0.005,
|
||||
3,
|
||||
0.9885903068210383
|
||||
],
|
||||
[
|
||||
0.01,
|
||||
3,
|
||||
0.9801597431201753
|
||||
],
|
||||
[
|
||||
0.015,
|
||||
3,
|
||||
0.9801597431201753
|
||||
],
|
||||
[
|
||||
0.02,
|
||||
2,
|
||||
0.9680925119257522
|
||||
],
|
||||
[
|
||||
0.03,
|
||||
2,
|
||||
0.9680925119257522
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
2,
|
||||
0.9680925119257522
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
1,
|
||||
0.8667444738394041
|
||||
]
|
||||
]
|
||||
},
|
||||
"top": {
|
||||
"results": [
|
||||
{
|
||||
"threshold": 0.0,
|
||||
"nz": 17,
|
||||
"r2": 0.9947943200325069,
|
||||
"mae": 0.01388285452459937,
|
||||
"weights_min": 0.3642388297379152,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.001,
|
||||
"nz": 15,
|
||||
"r2": 0.9947724285032213,
|
||||
"mae": 0.013998153842830187,
|
||||
"weights_min": 0.3642388297379152,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.002,
|
||||
"nz": 15,
|
||||
"r2": 0.9947724285032213,
|
||||
"mae": 0.013998153842830187,
|
||||
"weights_min": 0.3642388297379152,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.005,
|
||||
"nz": 14,
|
||||
"r2": 0.9947437372987523,
|
||||
"mae": 0.013973763318069576,
|
||||
"weights_min": 0.3642388297379152,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.01,
|
||||
"nz": 11,
|
||||
"r2": 0.994527427094902,
|
||||
"mae": 0.014375559061365345,
|
||||
"weights_min": 0.3642388297379152,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.015,
|
||||
"nz": 10,
|
||||
"r2": 0.9930561323361152,
|
||||
"mae": 0.015350427162982516,
|
||||
"weights_min": 0.3642388297379152,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.02,
|
||||
"nz": 10,
|
||||
"r2": 0.9930561323361152,
|
||||
"mae": 0.015350427162982516,
|
||||
"weights_min": 0.3642388297379152,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.03,
|
||||
"nz": 9,
|
||||
"r2": 0.9923352206869693,
|
||||
"mae": 0.016117400302495512,
|
||||
"weights_min": 0.3642388297379152,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.05,
|
||||
"nz": 5,
|
||||
"r2": 0.9832113360018212,
|
||||
"mae": 0.02344478050006772,
|
||||
"weights_min": 0.3642388297379152,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
{
|
||||
"threshold": 0.1,
|
||||
"nz": 2,
|
||||
"r2": 0.5190549772066559,
|
||||
"mae": 0.1224813760307,
|
||||
"weights_min": 0.3642388297379152,
|
||||
"weights_max": 1.1067365435175973
|
||||
}
|
||||
],
|
||||
"best": {
|
||||
"threshold": 0.002,
|
||||
"nz": 15,
|
||||
"r2": 0.9947724285032213,
|
||||
"mae": 0.013998153842830187,
|
||||
"weights_min": 0.3642388297379152,
|
||||
"weights_max": 1.1067365435175973
|
||||
},
|
||||
"best_coef": [
|
||||
1.0021483455333764,
|
||||
-0.008212536312529608,
|
||||
-0.008095982403317927,
|
||||
0.0033883289805039874,
|
||||
-0.0014027415625294862,
|
||||
-0.043634070706600914,
|
||||
0.034508992736236595,
|
||||
0.09250796489630796,
|
||||
0.046370682051450104,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0035461180448679397,
|
||||
0.009932878542230005,
|
||||
0.002841799103744343,
|
||||
-0.0009874050179528864,
|
||||
-0.0039603133924009494,
|
||||
0.0051583627341490485
|
||||
],
|
||||
"sparsity_curve": [
|
||||
[
|
||||
0.0,
|
||||
17,
|
||||
0.9947943200325069
|
||||
],
|
||||
[
|
||||
0.001,
|
||||
15,
|
||||
0.9947724285032213
|
||||
],
|
||||
[
|
||||
0.002,
|
||||
15,
|
||||
0.9947724285032213
|
||||
],
|
||||
[
|
||||
0.005,
|
||||
14,
|
||||
0.9947437372987523
|
||||
],
|
||||
[
|
||||
0.01,
|
||||
11,
|
||||
0.994527427094902
|
||||
],
|
||||
[
|
||||
0.015,
|
||||
10,
|
||||
0.9930561323361152
|
||||
],
|
||||
[
|
||||
0.02,
|
||||
10,
|
||||
0.9930561323361152
|
||||
],
|
||||
[
|
||||
0.03,
|
||||
9,
|
||||
0.9923352206869693
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
5,
|
||||
0.9832113360018212
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
2,
|
||||
0.5190549772066559
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,996 @@
|
||||
{
|
||||
"thresholds": [
|
||||
0.0,
|
||||
0.001,
|
||||
0.002,
|
||||
0.005,
|
||||
0.01,
|
||||
0.015,
|
||||
0.02,
|
||||
0.03,
|
||||
0.05,
|
||||
0.1
|
||||
],
|
||||
"per_scene": {
|
||||
"vortex_lamb": {
|
||||
"scene": "vortex_lamb",
|
||||
"re_code": 100,
|
||||
"mu": 0.02,
|
||||
"n_samples": 148,
|
||||
"feature_names_front": [
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT",
|
||||
"mu",
|
||||
"mu_u_a",
|
||||
"mu_v_a",
|
||||
"mu_Cd_tot",
|
||||
"mu_Cl_diff"
|
||||
],
|
||||
"feature_names_rear": [
|
||||
"bias",
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT",
|
||||
"mu",
|
||||
"mu_u_a",
|
||||
"mu_v_a",
|
||||
"mu_Cd_tot",
|
||||
"mu_Cl_diff"
|
||||
],
|
||||
"front": {
|
||||
"results": [
|
||||
{
|
||||
"threshold": 0.0,
|
||||
"nz": 21,
|
||||
"r2": 0.9035051679446613,
|
||||
"mae": 0.05502827225008196
|
||||
},
|
||||
{
|
||||
"threshold": 0.001,
|
||||
"nz": 20,
|
||||
"r2": 0.9035028044287374,
|
||||
"mae": 0.054966606007031876
|
||||
},
|
||||
{
|
||||
"threshold": 0.002,
|
||||
"nz": 20,
|
||||
"r2": 0.9035028044287374,
|
||||
"mae": 0.054966606007031876
|
||||
},
|
||||
{
|
||||
"threshold": 0.005,
|
||||
"nz": 16,
|
||||
"r2": 0.9017891237504362,
|
||||
"mae": 0.053710513734883655
|
||||
},
|
||||
{
|
||||
"threshold": 0.01,
|
||||
"nz": 9,
|
||||
"r2": 0.8985847902462778,
|
||||
"mae": 0.054491226319598914
|
||||
},
|
||||
{
|
||||
"threshold": 0.015,
|
||||
"nz": 8,
|
||||
"r2": 0.8957625139671737,
|
||||
"mae": 0.05306021520916354
|
||||
},
|
||||
{
|
||||
"threshold": 0.02,
|
||||
"nz": 8,
|
||||
"r2": 0.8957625139671737,
|
||||
"mae": 0.05306021520916354
|
||||
},
|
||||
{
|
||||
"threshold": 0.03,
|
||||
"nz": 8,
|
||||
"r2": 0.8957625139671737,
|
||||
"mae": 0.05306021520916354
|
||||
},
|
||||
{
|
||||
"threshold": 0.05,
|
||||
"nz": 3,
|
||||
"r2": 0.8536388609680176,
|
||||
"mae": 0.048637995761707624
|
||||
},
|
||||
{
|
||||
"threshold": 0.1,
|
||||
"nz": 3,
|
||||
"r2": 0.8536388609680176,
|
||||
"mae": 0.048637995761707624
|
||||
}
|
||||
],
|
||||
"best": {
|
||||
"threshold": 0.0,
|
||||
"nz": 21,
|
||||
"r2": 0.9035051679446613,
|
||||
"mae": 0.05502827225008196
|
||||
},
|
||||
"best_coef": [
|
||||
0.0072499249196507284,
|
||||
-0.013406647625693383,
|
||||
-0.00038101504054493135,
|
||||
-0.01577043426582744,
|
||||
-0.021357793291808133,
|
||||
0.09538149016633536,
|
||||
-0.17597430070013861,
|
||||
0.01105460767691196,
|
||||
0.013467531810937875,
|
||||
-0.008447877114831191,
|
||||
-0.009842767133851753,
|
||||
0.019209968175028087,
|
||||
-0.036801729600496,
|
||||
0.0036358387699529284,
|
||||
0.006079481319894673,
|
||||
0.003342294121453103,
|
||||
-0.2971343137386559,
|
||||
-0.6703323813926846,
|
||||
-0.7885217073102587,
|
||||
-1.0678896759007668,
|
||||
0.5527301613931733
|
||||
],
|
||||
"sparsity_curve": [
|
||||
[
|
||||
0.0,
|
||||
21,
|
||||
0.9035051679446613
|
||||
],
|
||||
[
|
||||
0.001,
|
||||
20,
|
||||
0.9035028044287374
|
||||
],
|
||||
[
|
||||
0.002,
|
||||
20,
|
||||
0.9035028044287374
|
||||
],
|
||||
[
|
||||
0.005,
|
||||
16,
|
||||
0.9017891237504362
|
||||
],
|
||||
[
|
||||
0.01,
|
||||
9,
|
||||
0.8985847902462778
|
||||
],
|
||||
[
|
||||
0.015,
|
||||
8,
|
||||
0.8957625139671737
|
||||
],
|
||||
[
|
||||
0.02,
|
||||
8,
|
||||
0.8957625139671737
|
||||
],
|
||||
[
|
||||
0.03,
|
||||
8,
|
||||
0.8957625139671737
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
3,
|
||||
0.8536388609680176
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
3,
|
||||
0.8536388609680176
|
||||
]
|
||||
]
|
||||
},
|
||||
"top": {
|
||||
"results": [
|
||||
{
|
||||
"threshold": 0.0,
|
||||
"nz": 22,
|
||||
"r2": 0.979810012198325,
|
||||
"mae": 0.009405479490894075
|
||||
},
|
||||
{
|
||||
"threshold": 0.001,
|
||||
"nz": 20,
|
||||
"r2": 0.9797408009698567,
|
||||
"mae": 0.009464924709826631
|
||||
},
|
||||
{
|
||||
"threshold": 0.002,
|
||||
"nz": 19,
|
||||
"r2": 0.9796029724451923,
|
||||
"mae": 0.009503048001896178
|
||||
},
|
||||
{
|
||||
"threshold": 0.005,
|
||||
"nz": 6,
|
||||
"r2": 0.9752589669369754,
|
||||
"mae": 0.009083428201966606
|
||||
},
|
||||
{
|
||||
"threshold": 0.01,
|
||||
"nz": 5,
|
||||
"r2": 0.9685659511773673,
|
||||
"mae": 0.01027038394304665
|
||||
},
|
||||
{
|
||||
"threshold": 0.015,
|
||||
"nz": 2,
|
||||
"r2": 0.9602153300731789,
|
||||
"mae": 0.012152564325363832
|
||||
},
|
||||
{
|
||||
"threshold": 0.02,
|
||||
"nz": 2,
|
||||
"r2": 0.9602153300731789,
|
||||
"mae": 0.012152564325363832
|
||||
},
|
||||
{
|
||||
"threshold": 0.03,
|
||||
"nz": 2,
|
||||
"r2": 0.9602153300731789,
|
||||
"mae": 0.012152564325363832
|
||||
},
|
||||
{
|
||||
"threshold": 0.05,
|
||||
"nz": 1,
|
||||
"r2": 0.9262664550660489,
|
||||
"mae": 0.013270022046144844
|
||||
},
|
||||
{
|
||||
"threshold": 0.1,
|
||||
"nz": 0,
|
||||
"r2": -0.2926478447353347,
|
||||
"mae": 0.10377883511859723
|
||||
}
|
||||
],
|
||||
"best": {
|
||||
"threshold": 0.0,
|
||||
"nz": 22,
|
||||
"r2": 0.979810012198325,
|
||||
"mae": 0.009405479490894075
|
||||
},
|
||||
"best_coef": [
|
||||
1.7326565320927485,
|
||||
-0.021510750075876994,
|
||||
0.0007162636287450304,
|
||||
0.003690011764588065,
|
||||
-0.001255780396435901,
|
||||
0.008069876064011276,
|
||||
-0.027165643005235728,
|
||||
0.019732103606457083,
|
||||
-0.007023240411992188,
|
||||
-0.00413143280625655,
|
||||
0.0016423995129504244,
|
||||
0.0008079534031552331,
|
||||
-0.005050487340309005,
|
||||
0.011582526033145867,
|
||||
0.0010455718346845003,
|
||||
0.0012590379370475096,
|
||||
0.0019097817325384912,
|
||||
0.0346531306245988,
|
||||
0.03581318435812541,
|
||||
-0.06278853147020641,
|
||||
0.40349380438892807,
|
||||
-0.3511614171629877
|
||||
],
|
||||
"sparsity_curve": [
|
||||
[
|
||||
0.0,
|
||||
22,
|
||||
0.979810012198325
|
||||
],
|
||||
[
|
||||
0.001,
|
||||
20,
|
||||
0.9797408009698567
|
||||
],
|
||||
[
|
||||
0.002,
|
||||
19,
|
||||
0.9796029724451923
|
||||
],
|
||||
[
|
||||
0.005,
|
||||
6,
|
||||
0.9752589669369754
|
||||
],
|
||||
[
|
||||
0.01,
|
||||
5,
|
||||
0.9685659511773673
|
||||
],
|
||||
[
|
||||
0.015,
|
||||
2,
|
||||
0.9602153300731789
|
||||
],
|
||||
[
|
||||
0.02,
|
||||
2,
|
||||
0.9602153300731789
|
||||
],
|
||||
[
|
||||
0.03,
|
||||
2,
|
||||
0.9602153300731789
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
1,
|
||||
0.9262664550660489
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0,
|
||||
-0.2926478447353347
|
||||
]
|
||||
]
|
||||
},
|
||||
"bottom": {
|
||||
"results": [
|
||||
{
|
||||
"threshold": 0.0,
|
||||
"nz": 22,
|
||||
"r2": 0.9334422885170565,
|
||||
"mae": 0.0062053698726041735
|
||||
},
|
||||
{
|
||||
"threshold": 0.001,
|
||||
"nz": 15,
|
||||
"r2": 0.9318911728011019,
|
||||
"mae": 0.00612106433470266
|
||||
},
|
||||
{
|
||||
"threshold": 0.002,
|
||||
"nz": 11,
|
||||
"r2": 0.9294742132351927,
|
||||
"mae": 0.006263040564511156
|
||||
},
|
||||
{
|
||||
"threshold": 0.005,
|
||||
"nz": 7,
|
||||
"r2": 0.8963211646824344,
|
||||
"mae": 0.006779203944819282
|
||||
},
|
||||
{
|
||||
"threshold": 0.01,
|
||||
"nz": 5,
|
||||
"r2": 0.8721441125489685,
|
||||
"mae": 0.007291293800356046
|
||||
},
|
||||
{
|
||||
"threshold": 0.015,
|
||||
"nz": 1,
|
||||
"r2": 0.6935730348615337,
|
||||
"mae": 0.009771975563999018
|
||||
},
|
||||
{
|
||||
"threshold": 0.02,
|
||||
"nz": 1,
|
||||
"r2": 0.6935730348615337,
|
||||
"mae": 0.009771975563999018
|
||||
},
|
||||
{
|
||||
"threshold": 0.03,
|
||||
"nz": 1,
|
||||
"r2": 3.300804074513053e-12,
|
||||
"mae": 0.029445380091027484
|
||||
},
|
||||
{
|
||||
"threshold": 0.05,
|
||||
"nz": 1,
|
||||
"r2": 3.300804074513053e-12,
|
||||
"mae": 0.029445380091027484
|
||||
},
|
||||
{
|
||||
"threshold": 0.1,
|
||||
"nz": 0,
|
||||
"r2": -5.4349952892154265,
|
||||
"mae": 0.0796928089615461
|
||||
}
|
||||
],
|
||||
"best": {
|
||||
"threshold": 0.0,
|
||||
"nz": 22,
|
||||
"r2": 0.9334422885170565,
|
||||
"mae": 0.0062053698726041735
|
||||
},
|
||||
"best_coef": [
|
||||
0.6365299396095444,
|
||||
-0.00680014903595817,
|
||||
-0.0014763845224131282,
|
||||
0.0008331648138976364,
|
||||
-0.0013963333722837737,
|
||||
0.0026865900945637236,
|
||||
-0.014425589645304323,
|
||||
-0.008472370593784707,
|
||||
-6.004332296000475e-05,
|
||||
-0.0014926889561804521,
|
||||
-0.0004258139447154254,
|
||||
-0.0018644416734531306,
|
||||
0.006364757842372448,
|
||||
-0.003199874412701356,
|
||||
0.001370932025212518,
|
||||
0.002115447057480394,
|
||||
0.0019992859663057654,
|
||||
0.012730598783987558,
|
||||
-0.07381922521108229,
|
||||
-0.069816526655473,
|
||||
0.13432950141437106,
|
||||
-0.0030019765287261236
|
||||
],
|
||||
"sparsity_curve": [
|
||||
[
|
||||
0.0,
|
||||
22,
|
||||
0.9334422885170565
|
||||
],
|
||||
[
|
||||
0.001,
|
||||
15,
|
||||
0.9318911728011019
|
||||
],
|
||||
[
|
||||
0.002,
|
||||
11,
|
||||
0.9294742132351927
|
||||
],
|
||||
[
|
||||
0.005,
|
||||
7,
|
||||
0.8963211646824344
|
||||
],
|
||||
[
|
||||
0.01,
|
||||
5,
|
||||
0.8721441125489685
|
||||
],
|
||||
[
|
||||
0.015,
|
||||
1,
|
||||
0.6935730348615337
|
||||
],
|
||||
[
|
||||
0.02,
|
||||
1,
|
||||
0.6935730348615337
|
||||
],
|
||||
[
|
||||
0.03,
|
||||
1,
|
||||
3.300804074513053e-12
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
1,
|
||||
3.300804074513053e-12
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0,
|
||||
-5.4349952892154265
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"vortex_taylor": {
|
||||
"scene": "vortex_taylor",
|
||||
"re_code": 100,
|
||||
"mu": 0.02,
|
||||
"n_samples": 148,
|
||||
"feature_names_front": [
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT",
|
||||
"mu",
|
||||
"mu_u_a",
|
||||
"mu_v_a",
|
||||
"mu_Cd_tot",
|
||||
"mu_Cl_diff"
|
||||
],
|
||||
"feature_names_rear": [
|
||||
"bias",
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"sin_ua",
|
||||
"cos_ua",
|
||||
"aF_lag1",
|
||||
"aB_lag1",
|
||||
"aT_lag1",
|
||||
"daF",
|
||||
"daB",
|
||||
"daT",
|
||||
"mu",
|
||||
"mu_u_a",
|
||||
"mu_v_a",
|
||||
"mu_Cd_tot",
|
||||
"mu_Cl_diff"
|
||||
],
|
||||
"front": {
|
||||
"results": [
|
||||
{
|
||||
"threshold": 0.0,
|
||||
"nz": 21,
|
||||
"r2": 0.9603622630700551,
|
||||
"mae": 5.5722956333111334e-05
|
||||
},
|
||||
{
|
||||
"threshold": 0.001,
|
||||
"nz": 0,
|
||||
"r2": -1762.7026716770156,
|
||||
"mae": 0.019129430850011273
|
||||
},
|
||||
{
|
||||
"threshold": 0.002,
|
||||
"nz": 0,
|
||||
"r2": -1762.7026716770156,
|
||||
"mae": 0.019129430850011273
|
||||
},
|
||||
{
|
||||
"threshold": 0.005,
|
||||
"nz": 0,
|
||||
"r2": -1762.7026716770156,
|
||||
"mae": 0.019129430850011273
|
||||
},
|
||||
{
|
||||
"threshold": 0.01,
|
||||
"nz": 0,
|
||||
"r2": -1762.7026716770156,
|
||||
"mae": 0.019129430850011273
|
||||
},
|
||||
{
|
||||
"threshold": 0.015,
|
||||
"nz": 0,
|
||||
"r2": -1762.7026716770156,
|
||||
"mae": 0.019129430850011273
|
||||
},
|
||||
{
|
||||
"threshold": 0.02,
|
||||
"nz": 0,
|
||||
"r2": -1762.7026716770156,
|
||||
"mae": 0.019129430850011273
|
||||
},
|
||||
{
|
||||
"threshold": 0.03,
|
||||
"nz": 0,
|
||||
"r2": -1762.7026716770156,
|
||||
"mae": 0.019129430850011273
|
||||
},
|
||||
{
|
||||
"threshold": 0.05,
|
||||
"nz": 0,
|
||||
"r2": -1762.7026716770156,
|
||||
"mae": 0.019129430850011273
|
||||
},
|
||||
{
|
||||
"threshold": 0.1,
|
||||
"nz": 0,
|
||||
"r2": -1762.7026716770156,
|
||||
"mae": 0.019129430850011273
|
||||
}
|
||||
],
|
||||
"best": {
|
||||
"threshold": 0.0,
|
||||
"nz": 21,
|
||||
"r2": 0.9603622630700551,
|
||||
"mae": 5.5722956333111334e-05
|
||||
},
|
||||
"best_coef": [
|
||||
0.00013185241334928363,
|
||||
0.0013869486093058166,
|
||||
-2.0689454061431898e-05,
|
||||
0.0003650495654675631,
|
||||
-7.646260510377518e-05,
|
||||
0.0016834710794748663,
|
||||
0.002138870811614627,
|
||||
0.0009672545588015969,
|
||||
-0.0011958663539923654,
|
||||
-0.00015017143903531285,
|
||||
0.007403929744140764,
|
||||
-0.0015484862269750206,
|
||||
-0.0003240821985992223,
|
||||
-0.0010978795962499714,
|
||||
-0.0002774795287867582,
|
||||
-0.00041159658606479107,
|
||||
0.00011190538695352297,
|
||||
0.06934742736821846,
|
||||
0.018252511507361284,
|
||||
-0.0038231311262574906,
|
||||
0.04836265570630274
|
||||
],
|
||||
"sparsity_curve": [
|
||||
[
|
||||
0.0,
|
||||
21,
|
||||
0.9603622630700551
|
||||
],
|
||||
[
|
||||
0.001,
|
||||
0,
|
||||
-1762.7026716770156
|
||||
],
|
||||
[
|
||||
0.002,
|
||||
0,
|
||||
-1762.7026716770156
|
||||
],
|
||||
[
|
||||
0.005,
|
||||
0,
|
||||
-1762.7026716770156
|
||||
],
|
||||
[
|
||||
0.01,
|
||||
0,
|
||||
-1762.7026716770156
|
||||
],
|
||||
[
|
||||
0.015,
|
||||
0,
|
||||
-1762.7026716770156
|
||||
],
|
||||
[
|
||||
0.02,
|
||||
0,
|
||||
-1762.7026716770156
|
||||
],
|
||||
[
|
||||
0.03,
|
||||
0,
|
||||
-1762.7026716770156
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
0,
|
||||
-1762.7026716770156
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0,
|
||||
-1762.7026716770156
|
||||
]
|
||||
]
|
||||
},
|
||||
"top": {
|
||||
"results": [
|
||||
{
|
||||
"threshold": 0.0,
|
||||
"nz": 22,
|
||||
"r2": 0.809824114603052,
|
||||
"mae": 0.00019280734797529785
|
||||
},
|
||||
{
|
||||
"threshold": 0.001,
|
||||
"nz": 1,
|
||||
"r2": 4.909409545561516e-09,
|
||||
"mae": 0.0004627442799109909
|
||||
},
|
||||
{
|
||||
"threshold": 0.002,
|
||||
"nz": 1,
|
||||
"r2": 4.909409545561516e-09,
|
||||
"mae": 0.0004627442799109909
|
||||
},
|
||||
{
|
||||
"threshold": 0.005,
|
||||
"nz": 0,
|
||||
"r2": -3813.3981416722418,
|
||||
"mae": 0.06224470555379584
|
||||
},
|
||||
{
|
||||
"threshold": 0.01,
|
||||
"nz": 0,
|
||||
"r2": -3813.3981416722418,
|
||||
"mae": 0.06224470555379584
|
||||
},
|
||||
{
|
||||
"threshold": 0.015,
|
||||
"nz": 0,
|
||||
"r2": -3813.3981416722418,
|
||||
"mae": 0.06224470555379584
|
||||
},
|
||||
{
|
||||
"threshold": 0.02,
|
||||
"nz": 0,
|
||||
"r2": -3813.3981416722418,
|
||||
"mae": 0.06224470555379584
|
||||
},
|
||||
{
|
||||
"threshold": 0.03,
|
||||
"nz": 0,
|
||||
"r2": -3813.3981416722418,
|
||||
"mae": 0.06224470555379584
|
||||
},
|
||||
{
|
||||
"threshold": 0.05,
|
||||
"nz": 0,
|
||||
"r2": -3813.3981416722418,
|
||||
"mae": 0.06224470555379584
|
||||
},
|
||||
{
|
||||
"threshold": 0.1,
|
||||
"nz": 0,
|
||||
"r2": -3813.3981416722418,
|
||||
"mae": 0.06224470555379584
|
||||
}
|
||||
],
|
||||
"best": {
|
||||
"threshold": 0.0,
|
||||
"nz": 22,
|
||||
"r2": 0.809824114603052,
|
||||
"mae": 0.00019280734797529785
|
||||
},
|
||||
"best_coef": [
|
||||
-0.003855648809544881,
|
||||
-0.00016402917649747364,
|
||||
-0.00930469925984968,
|
||||
0.0003725286141146794,
|
||||
-0.0018143741612594137,
|
||||
-0.0006228672933056743,
|
||||
-0.004123657830294623,
|
||||
0.009617379353839065,
|
||||
-0.0020693580870050163,
|
||||
0.0064472830467429834,
|
||||
-0.0009363904689749538,
|
||||
0.002848747579355727,
|
||||
0.008718629599353982,
|
||||
0.006611618826853361,
|
||||
0.0026442625498493562,
|
||||
-0.000822158875902874,
|
||||
-0.00019526846815097482,
|
||||
-7.71129751901901e-05,
|
||||
-0.4652349584088788,
|
||||
-0.09071890000133181,
|
||||
-0.031143453311218216,
|
||||
-0.10346632929440941
|
||||
],
|
||||
"sparsity_curve": [
|
||||
[
|
||||
0.0,
|
||||
22,
|
||||
0.809824114603052
|
||||
],
|
||||
[
|
||||
0.001,
|
||||
1,
|
||||
4.909409545561516e-09
|
||||
],
|
||||
[
|
||||
0.002,
|
||||
1,
|
||||
4.909409545561516e-09
|
||||
],
|
||||
[
|
||||
0.005,
|
||||
0,
|
||||
-3813.3981416722418
|
||||
],
|
||||
[
|
||||
0.01,
|
||||
0,
|
||||
-3813.3981416722418
|
||||
],
|
||||
[
|
||||
0.015,
|
||||
0,
|
||||
-3813.3981416722418
|
||||
],
|
||||
[
|
||||
0.02,
|
||||
0,
|
||||
-3813.3981416722418
|
||||
],
|
||||
[
|
||||
0.03,
|
||||
0,
|
||||
-3813.3981416722418
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
0,
|
||||
-3813.3981416722418
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0,
|
||||
-3813.3981416722418
|
||||
]
|
||||
]
|
||||
},
|
||||
"bottom": {
|
||||
"results": [
|
||||
{
|
||||
"threshold": 0.0,
|
||||
"nz": 22,
|
||||
"r2": 0.6431303693566448,
|
||||
"mae": 0.00012115305583366485
|
||||
},
|
||||
{
|
||||
"threshold": 0.001,
|
||||
"nz": 1,
|
||||
"r2": 2.5346330034814457e-08,
|
||||
"mae": 0.00029202565622359403
|
||||
},
|
||||
{
|
||||
"threshold": 0.002,
|
||||
"nz": 1,
|
||||
"r2": 2.5346330034814457e-08,
|
||||
"mae": 0.00029202565622359403
|
||||
},
|
||||
{
|
||||
"threshold": 0.005,
|
||||
"nz": 1,
|
||||
"r2": 2.5346330034814457e-08,
|
||||
"mae": 0.00029202565622359403
|
||||
},
|
||||
{
|
||||
"threshold": 0.01,
|
||||
"nz": 1,
|
||||
"r2": 2.5346330034814457e-08,
|
||||
"mae": 0.00029202565622359403
|
||||
},
|
||||
{
|
||||
"threshold": 0.015,
|
||||
"nz": 1,
|
||||
"r2": 2.5346330034814457e-08,
|
||||
"mae": 0.00029202565622359403
|
||||
},
|
||||
{
|
||||
"threshold": 0.02,
|
||||
"nz": 1,
|
||||
"r2": 2.5346330034814457e-08,
|
||||
"mae": 0.00029202565622359403
|
||||
},
|
||||
{
|
||||
"threshold": 0.03,
|
||||
"nz": 0,
|
||||
"r2": -11389.175969107222,
|
||||
"mae": 0.05019249195686063
|
||||
},
|
||||
{
|
||||
"threshold": 0.05,
|
||||
"nz": 0,
|
||||
"r2": -11389.175969107222,
|
||||
"mae": 0.05019249195686063
|
||||
},
|
||||
{
|
||||
"threshold": 0.1,
|
||||
"nz": 0,
|
||||
"r2": -11389.175969107222,
|
||||
"mae": 0.05019249195686063
|
||||
}
|
||||
],
|
||||
"best": {
|
||||
"threshold": 0.0,
|
||||
"nz": 22,
|
||||
"r2": 0.6431303693566448,
|
||||
"mae": 0.00012115305583366485
|
||||
},
|
||||
"best_coef": [
|
||||
0.024327554221764875,
|
||||
-0.0005249278989068122,
|
||||
-0.0012993577286068104,
|
||||
2.2680966036791235e-07,
|
||||
-0.00010725143675978186,
|
||||
-6.83864821520398e-05,
|
||||
0.0010096871646746155,
|
||||
0.010716542986185212,
|
||||
0.0009908500661735154,
|
||||
0.0011374615793514392,
|
||||
0.0001758268322788275,
|
||||
-0.0008997304730805852,
|
||||
-0.0002053415257431248,
|
||||
0.0003868365622255378,
|
||||
0.005272105474899691,
|
||||
0.0033010584355117824,
|
||||
0.0027208004849191268,
|
||||
0.0004865510823514911,
|
||||
-0.06496786884052097,
|
||||
-0.005364174292120229,
|
||||
-0.003419346453559459,
|
||||
0.04954205911186436
|
||||
],
|
||||
"sparsity_curve": [
|
||||
[
|
||||
0.0,
|
||||
22,
|
||||
0.6431303693566448
|
||||
],
|
||||
[
|
||||
0.001,
|
||||
1,
|
||||
2.5346330034814457e-08
|
||||
],
|
||||
[
|
||||
0.002,
|
||||
1,
|
||||
2.5346330034814457e-08
|
||||
],
|
||||
[
|
||||
0.005,
|
||||
1,
|
||||
2.5346330034814457e-08
|
||||
],
|
||||
[
|
||||
0.01,
|
||||
1,
|
||||
2.5346330034814457e-08
|
||||
],
|
||||
[
|
||||
0.015,
|
||||
1,
|
||||
2.5346330034814457e-08
|
||||
],
|
||||
[
|
||||
0.02,
|
||||
1,
|
||||
2.5346330034814457e-08
|
||||
],
|
||||
[
|
||||
0.03,
|
||||
0,
|
||||
-11389.175969107222
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
0,
|
||||
-11389.175969107222
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0,
|
||||
-11389.175969107222
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"scene": "illusion_0.5L",
|
||||
"mode": "pysr",
|
||||
"similarity_full": 0.8539735529506018,
|
||||
"similarity_tail": 0.8411474326454078,
|
||||
"action_range": 0.06714382640888465,
|
||||
"n_steps": 320
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"scene": "illusion_0.6L",
|
||||
"mode": "pysr",
|
||||
"similarity_full": 0.9388972369369757,
|
||||
"similarity_tail": 0.8608654259522963,
|
||||
"action_range": 0.044579733956375364,
|
||||
"n_steps": 320
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"scene": "illusion_0.75L",
|
||||
"mode": "pysr",
|
||||
"similarity_full": 0.9821949471763758,
|
||||
"similarity_tail": 0.8071620435178003,
|
||||
"action_range": 0.029841950903943048,
|
||||
"n_steps": 320
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"scene": "illusion_0.75L",
|
||||
"mode": "v23",
|
||||
"similarity_full": 0.9741372518705987,
|
||||
"similarity_tail": 0.9726050667188786,
|
||||
"action_range": 0.03237645857182351,
|
||||
"n_steps": 320,
|
||||
"threshold": "best"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"scene": "illusion_0.8L",
|
||||
"mode": "pysr",
|
||||
"similarity_full": 0.9076366235277858,
|
||||
"similarity_tail": 0.9003715798241534,
|
||||
"action_range": 0.02705657196270742,
|
||||
"n_steps": 214
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"scene": "illusion_1.2L",
|
||||
"mode": "pysr",
|
||||
"similarity_full": 0.8485137980740682,
|
||||
"similarity_tail": 0.7692440834631539,
|
||||
"action_range": 0.026140261986299245,
|
||||
"n_steps": 214
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"scene": "illusion_1.5L",
|
||||
"mode": "v23",
|
||||
"similarity_full": 0.9296044171184163,
|
||||
"similarity_tail": 0.925839316423258,
|
||||
"action_range": 0.035437546689072105,
|
||||
"n_steps": 200,
|
||||
"threshold": "best"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"scene": "illusion_1L",
|
||||
"mode": "pysr",
|
||||
"similarity_full": 0.9580609580562278,
|
||||
"similarity_tail": 0.8857815231916633,
|
||||
"action_range": 0.011634223590664046,
|
||||
"n_steps": 214
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"scene": "illusion_1L",
|
||||
"mode": "pysr",
|
||||
"similarity_full": 0.9580609580562278,
|
||||
"similarity_tail": 0.8857815231916633,
|
||||
"action_range": 0.011634223590664046,
|
||||
"n_steps": 214
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"scene": "illusion_1L",
|
||||
"mode": "v23",
|
||||
"similarity_full": 0.9581664533499054,
|
||||
"similarity_tail": 0.9575937863460072,
|
||||
"action_range": 0.014234293670783398,
|
||||
"n_steps": 320,
|
||||
"threshold": "best"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"scene": "illusion_2L",
|
||||
"mode": "pysr",
|
||||
"similarity_full": 0.6754607445898861,
|
||||
"similarity_tail": 0.6292225479264744,
|
||||
"action_range": 0.3686004659586289,
|
||||
"n_steps": 160
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"scene": "karman_joint",
|
||||
"scene_id": "karman",
|
||||
"channel": "front",
|
||||
"output": "alpha",
|
||||
"feature_names": [
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"daF_dt",
|
||||
"daB_dt",
|
||||
"daT_dt",
|
||||
"mu",
|
||||
"mu_u_a",
|
||||
"mu_v_a",
|
||||
"mu_Cd_tot",
|
||||
"mu_Cl_diff",
|
||||
"mu_Cl_tot"
|
||||
],
|
||||
"best_sympy": "daB_dt*0.38504666 + daF_dt + mu_Cl_tot*(-14.951645)",
|
||||
"best_score": 1.0
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"scene": "karman_joint",
|
||||
"scene_id": "karman",
|
||||
"channel": "top",
|
||||
"output": "alpha",
|
||||
"feature_names": [
|
||||
"bias",
|
||||
"u_m",
|
||||
"u_a",
|
||||
"u_c",
|
||||
"v_a",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cl_tot",
|
||||
"Cl_diff",
|
||||
"daF_dt",
|
||||
"daB_dt",
|
||||
"daT_dt",
|
||||
"mu",
|
||||
"mu_u_a",
|
||||
"mu_v_a",
|
||||
"mu_Cd_tot",
|
||||
"mu_Cl_diff",
|
||||
"mu_Cl_tot"
|
||||
],
|
||||
"best_sympy": "3.4138296",
|
||||
"best_score": 1.0
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re100",
|
||||
"mode": "abs",
|
||||
"similarity": 0.7001671047053404,
|
||||
"action_range": 0.8198985280719374,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re100",
|
||||
"mode": "deriv",
|
||||
"similarity": 0.6558668109381365,
|
||||
"action_range": 0.4967922429092896,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re100",
|
||||
"mode": "pysr",
|
||||
"similarity": 0.8801077359149027,
|
||||
"action_range": 0.05967765871961398,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re100",
|
||||
"mode": "pysr",
|
||||
"similarity": 0.888406234100047,
|
||||
"action_range": 0.0578484540630116,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re100",
|
||||
"mode": "pysr",
|
||||
"similarity": 0.8876964046102431,
|
||||
"action_range": 0.034138296000000005,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re100",
|
||||
"mode": "v23",
|
||||
"similarity": 0.9010299497208456,
|
||||
"action_range": 0.41788907540324977,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re150",
|
||||
"mode": "v23",
|
||||
"similarity": 0.5949698363534278,
|
||||
"action_range": 0.2098074207020967,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re200",
|
||||
"mode": "pysr",
|
||||
"similarity": 0.8448181642866177,
|
||||
"action_range": 0.034138296000000005,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re200",
|
||||
"mode": "v23",
|
||||
"similarity": 0.7930999192849009,
|
||||
"action_range": 0.36164324360459554,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re25",
|
||||
"mode": "v23",
|
||||
"similarity": 0.5670501132177096,
|
||||
"action_range": 0.386813219532425,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re300",
|
||||
"mode": "v23",
|
||||
"similarity": 0.5404784578855873,
|
||||
"action_range": 0.1695910099653411,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re400",
|
||||
"mode": "pysr",
|
||||
"similarity": 0.8058735756048312,
|
||||
"action_range": 0.034138296000000005,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re400",
|
||||
"mode": "pysr",
|
||||
"similarity": 0.7944157193756028,
|
||||
"action_range": 0.034138296000000005,
|
||||
"n_steps": 640
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re400",
|
||||
"mode": "pysr",
|
||||
"similarity": 0.8185568187903199,
|
||||
"action_range": 0.06124516065871972,
|
||||
"n_steps": 320
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re400",
|
||||
"mode": "v23",
|
||||
"similarity": 0.6642044711806294,
|
||||
"action_range": 0.17077547191291154,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re50",
|
||||
"mode": "pysr",
|
||||
"similarity": 0.8468594520598547,
|
||||
"action_range": 0.15152156686076074,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re50",
|
||||
"mode": "v23",
|
||||
"similarity": 0.5824068239398507,
|
||||
"action_range": 0.2252918496545665,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re70",
|
||||
"mode": "deriv",
|
||||
"similarity": 0.4273366537100325,
|
||||
"action_range": 0.25923786469074905,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scene": "karman_re70",
|
||||
"mode": "v23",
|
||||
"similarity": 0.5769877353631374,
|
||||
"action_range": 0.21521751562224534,
|
||||
"n_steps": 200
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"scene": "illusion_0.75L",
|
||||
"scene_id": "illusion",
|
||||
"channel": "front",
|
||||
"output": "alpha",
|
||||
"feature_names": [
|
||||
"u_a",
|
||||
"du_a_dt",
|
||||
"Cl_tot",
|
||||
"dCl_tot_dt",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cd_err",
|
||||
"Cl_err",
|
||||
"dCd_err_dt",
|
||||
"dCl_err_dt"
|
||||
],
|
||||
"equations": [
|
||||
{
|
||||
"complexity": 1,
|
||||
"loss": 1.1611668,
|
||||
"equation": "Cd_err",
|
||||
"score": 0.0,
|
||||
"sympy_format": "Cd_err",
|
||||
"lambda_format": "PySRFunction(X=>Cd_err)"
|
||||
},
|
||||
{
|
||||
"complexity": 2,
|
||||
"loss": 0.075797155,
|
||||
"equation": "-1.2395082",
|
||||
"score": 2.729119881666683,
|
||||
"sympy_format": "-1.23950820000000",
|
||||
"lambda_format": "PySRFunction(X=>-1.23950820000000)"
|
||||
},
|
||||
{
|
||||
"complexity": 4,
|
||||
"loss": 0.057897076,
|
||||
"equation": "Cl_err + -1.2561985",
|
||||
"score": 0.13469693826111778,
|
||||
"sympy_format": "Cl_err - 1.2561985",
|
||||
"lambda_format": "PySRFunction(X=>Cl_err - 1.2561985)"
|
||||
},
|
||||
{
|
||||
"complexity": 6,
|
||||
"loss": 0.03754608,
|
||||
"equation": "-1.2428339 - (dCl_tot_dt / Cd_tot)",
|
||||
"score": 0.21654895191031456,
|
||||
"sympy_format": "-1.2428339 - dCl_tot_dt/Cd_tot",
|
||||
"lambda_format": "PySRFunction(X=>-1.2428339 - dCl_tot_dt/Cd_tot)"
|
||||
},
|
||||
{
|
||||
"complexity": 8,
|
||||
"loss": 0.027650228,
|
||||
"equation": "-1.2424065 - ((dCl_tot_dt + Cl_tot) / Cd_tot)",
|
||||
"score": 0.15296750237696044,
|
||||
"sympy_format": "-1.2424065 - (Cl_tot + dCl_tot_dt)/Cd_tot",
|
||||
"lambda_format": "PySRFunction(X=>-1.2424065 - (Cl_tot + dCl_tot_dt)/Cd_tot)"
|
||||
},
|
||||
{
|
||||
"complexity": 9,
|
||||
"loss": 0.023363287,
|
||||
"equation": "-1.2398432 - ((Cl_tot + dCl_tot_dt) * 0.16933453)",
|
||||
"score": 0.1684681151879758,
|
||||
"sympy_format": "-0.16933453*(Cl_tot + dCl_tot_dt) - 1.2398432",
|
||||
"lambda_format": "PySRFunction(X=>-0.16933453*(Cl_tot + dCl_tot_dt) - 1.2398432)"
|
||||
},
|
||||
{
|
||||
"complexity": 11,
|
||||
"loss": 0.021574462,
|
||||
"equation": "((dCl_err_dt - (Cl_tot + dCl_tot_dt)) * 0.20579989) + -1.2389864",
|
||||
"score": 0.039827779143953225,
|
||||
"sympy_format": "(dCl_err_dt - (Cl_tot + dCl_tot_dt))*0.20579989 - 1.2389864",
|
||||
"lambda_format": "PySRFunction(X=>(dCl_err_dt - (Cl_tot + dCl_tot_dt))*0.20579989 - 1.2389864)"
|
||||
},
|
||||
{
|
||||
"complexity": 13,
|
||||
"loss": 0.020914195,
|
||||
"equation": "((Cl_err / Cd_tot) + -1.2402159) - ((Cl_tot + dCl_tot_dt) * 0.16267194)",
|
||||
"score": 0.015541092679475423,
|
||||
"sympy_format": "-0.16267194*(Cl_tot + dCl_tot_dt) - 1.2402159 + Cl_err/Cd_tot",
|
||||
"lambda_format": "PySRFunction(X=>-0.16267194*(Cl_tot + dCl_tot_dt) - 1.2402159 + Cl_err/Cd_tot)"
|
||||
},
|
||||
{
|
||||
"complexity": 15,
|
||||
"loss": 0.020151647,
|
||||
"equation": "(((Cl_err / Cd_rear) / Cd_tot) + -1.2398432) - ((Cl_tot + dCl_tot_dt) * 0.16933453)",
|
||||
"score": 0.01857104650284237,
|
||||
"sympy_format": "-0.16933453*(Cl_tot + dCl_tot_dt) - 1.2398432 + Cl_err/(Cd_rear*Cd_tot)",
|
||||
"lambda_format": "PySRFunction(X=>-0.16933453*(Cl_tot + dCl_tot_dt) - 1.2398432 + Cl_err/(Cd_rear*Cd_tot))"
|
||||
}
|
||||
],
|
||||
"best_sympy": "-0.16933453*(Cl_tot + dCl_tot_dt) - 1.2398432",
|
||||
"best_score": 0.6917657052732269
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
{
|
||||
"scene": "illusion_0.75L",
|
||||
"channel": "front",
|
||||
"output": "alpha",
|
||||
"feature_names": [
|
||||
"u_a",
|
||||
"du_a_dt",
|
||||
"Cl_tot",
|
||||
"dCl_tot_dt",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cd_err",
|
||||
"Cl_err",
|
||||
"dCd_err_dt",
|
||||
"dCl_err_dt",
|
||||
"target_Cd",
|
||||
"target_Cl"
|
||||
],
|
||||
"best_sympy": "-(dCl_tot_dt + target_Cl)/5.8401647 - 1.2372783",
|
||||
"best_score": 0.7232722304555419,
|
||||
"equations": [
|
||||
{
|
||||
"complexity": 1,
|
||||
"loss": 1.6359515,
|
||||
"equation": "Cl_err",
|
||||
"score": 0.0,
|
||||
"sympy_format": "Cl_err",
|
||||
"lambda_format": "PySRFunction(X=>Cl_err)"
|
||||
},
|
||||
{
|
||||
"complexity": 2,
|
||||
"loss": 0.075797155,
|
||||
"equation": "-1.2395153",
|
||||
"score": 3.071919112284068,
|
||||
"sympy_format": "-1.23951530000000",
|
||||
"lambda_format": "PySRFunction(X=>-1.23951530000000)"
|
||||
},
|
||||
{
|
||||
"complexity": 4,
|
||||
"loss": 0.057897076,
|
||||
"equation": "Cl_err - 1.2562019",
|
||||
"score": 0.13469693826111778,
|
||||
"sympy_format": "Cl_err - 1*1.2562019",
|
||||
"lambda_format": "PySRFunction(X=>Cl_err - 1*1.2562019)"
|
||||
},
|
||||
{
|
||||
"complexity": 6,
|
||||
"loss": 0.037532225,
|
||||
"equation": "-1.2431892 - (dCl_tot_dt / target_Cd)",
|
||||
"score": 0.2167334925729904,
|
||||
"sympy_format": "-dCl_tot_dt/target_Cd - 1.2431892",
|
||||
"lambda_format": "PySRFunction(X=>-dCl_tot_dt/target_Cd - 1.2431892)"
|
||||
},
|
||||
{
|
||||
"complexity": 8,
|
||||
"loss": 0.026256593,
|
||||
"equation": "-1.2326334 - ((Cl_tot + dCl_tot_dt) / target_Cd)",
|
||||
"score": 0.1786413889438378,
|
||||
"sympy_format": "-1.2326334 - (Cl_tot + dCl_tot_dt)/target_Cd",
|
||||
"lambda_format": "PySRFunction(X=>-1.2326334 - (Cl_tot + dCl_tot_dt)/target_Cd)"
|
||||
},
|
||||
{
|
||||
"complexity": 9,
|
||||
"loss": 0.020975176,
|
||||
"equation": "-1.2372783 - ((target_Cl + dCl_tot_dt) / 5.8401647)",
|
||||
"score": 0.22457747614686055,
|
||||
"sympy_format": "-(dCl_tot_dt + target_Cl)/5.8401647 - 1.2372783",
|
||||
"lambda_format": "PySRFunction(X=>-(dCl_tot_dt + target_Cl)/5.8401647 - 1.2372783)"
|
||||
},
|
||||
{
|
||||
"complexity": 10,
|
||||
"loss": 0.019975036,
|
||||
"equation": "-1.2351149 - ((dCl_tot_dt + target_Cl) / (target_Cd + Cd_rear))",
|
||||
"score": 0.0488563493561329,
|
||||
"sympy_format": "-1.2351149 - (dCl_tot_dt + target_Cl)/(Cd_rear + target_Cd)",
|
||||
"lambda_format": "PySRFunction(X=>-1.2351149 - (dCl_tot_dt + target_Cl)/(Cd_rear + target_Cd))"
|
||||
},
|
||||
{
|
||||
"complexity": 11,
|
||||
"loss": 0.018287793,
|
||||
"equation": "-1.2386359 - ((target_Cl + (dCl_tot_dt + dCd_err_dt)) / 5.8050957)",
|
||||
"score": 0.08824950581277256,
|
||||
"sympy_format": "-(dCd_err_dt + dCl_tot_dt + target_Cl)/5.8050957 - 1.2386359",
|
||||
"lambda_format": "PySRFunction(X=>-(dCd_err_dt + dCl_tot_dt + target_Cl)/5.8050957 - 1.2386359)"
|
||||
},
|
||||
{
|
||||
"complexity": 12,
|
||||
"loss": 0.016175408,
|
||||
"equation": "-1.2290057 - ((((dCd_err_dt + target_Cl) + dCl_tot_dt) / target_Cd) / Cd_rear)",
|
||||
"score": 0.12274172391063341,
|
||||
"sympy_format": "-1.2290057 - (dCd_err_dt + dCl_tot_dt + target_Cl)/(Cd_rear*target_Cd)",
|
||||
"lambda_format": "PySRFunction(X=>-1.2290057 - (dCd_err_dt + dCl_tot_dt + target_Cl)/(Cd_rear*target_Cd))"
|
||||
},
|
||||
{
|
||||
"complexity": 13,
|
||||
"loss": 0.01565276,
|
||||
"equation": "-1.2277503 - ((((dCl_tot_dt + dCd_err_dt) + target_Cl) / 3.854052) / Cd_rear)",
|
||||
"score": 0.03284480491569963,
|
||||
"sympy_format": "-1.2277503 - (dCd_err_dt + dCl_tot_dt + target_Cl)/(3.854052*Cd_rear)",
|
||||
"lambda_format": "PySRFunction(X=>-1.2277503 - (dCd_err_dt + dCl_tot_dt + target_Cl)/(3.854052*Cd_rear))"
|
||||
},
|
||||
{
|
||||
"complexity": 14,
|
||||
"loss": 0.014618657,
|
||||
"equation": "-1.1933857 - (((dCl_tot_dt + dCd_err_dt) + target_Cl) / ((target_Cd - target_Cl) * Cd_rear))",
|
||||
"score": 0.0683486696273396,
|
||||
"sympy_format": "-1.1933857 - (dCd_err_dt + dCl_tot_dt + target_Cl)/(Cd_rear*(target_Cd - target_Cl))",
|
||||
"lambda_format": "PySRFunction(X=>-1.1933857 - (dCd_err_dt + dCl_tot_dt + target_Cl)/(Cd_rear*(target_Cd - target_Cl)))"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
{
|
||||
"scene": "illusion_0.75L",
|
||||
"scene_id": "illusion",
|
||||
"channel": "top",
|
||||
"output": "alpha",
|
||||
"feature_names": [
|
||||
"bias",
|
||||
"u_a",
|
||||
"du_a_dt",
|
||||
"Cl_tot",
|
||||
"dCl_tot_dt",
|
||||
"Cd_tot",
|
||||
"Cd_rear",
|
||||
"Cd_err",
|
||||
"Cl_err",
|
||||
"dCd_err_dt",
|
||||
"dCl_err_dt"
|
||||
],
|
||||
"equations": [
|
||||
{
|
||||
"complexity": 1,
|
||||
"loss": 0.45252356,
|
||||
"equation": "Cd_rear",
|
||||
"score": 0.0,
|
||||
"sympy_format": "Cd_rear",
|
||||
"lambda_format": "PySRFunction(X=>Cd_rear)"
|
||||
},
|
||||
{
|
||||
"complexity": 2,
|
||||
"loss": 0.1519909,
|
||||
"equation": "1.8688796",
|
||||
"score": 1.0910191774498823,
|
||||
"sympy_format": "1.86887960000000",
|
||||
"lambda_format": "PySRFunction(X=>1.86887960000000)"
|
||||
},
|
||||
{
|
||||
"complexity": 4,
|
||||
"loss": 0.1296351,
|
||||
"equation": "Cl_err + 1.8521569",
|
||||
"score": 0.07954853502512871,
|
||||
"sympy_format": "Cl_err + 1.8521569",
|
||||
"lambda_format": "PySRFunction(X=>Cl_err + 1.8521569)"
|
||||
},
|
||||
{
|
||||
"complexity": 6,
|
||||
"loss": 0.075855345,
|
||||
"equation": "(dCl_tot_dt - Cd_tot) * -0.45136496",
|
||||
"score": 0.267947704620995,
|
||||
"sympy_format": "(-Cd_tot + dCl_tot_dt)*(-0.45136496)",
|
||||
"lambda_format": "PySRFunction(X=>(-Cd_tot + dCl_tot_dt)*(-0.45136496))"
|
||||
},
|
||||
{
|
||||
"complexity": 7,
|
||||
"loss": 0.06326852,
|
||||
"equation": "(u_a * -0.016224489) + 1.88584",
|
||||
"score": 0.18144028026845632,
|
||||
"sympy_format": "1.88584 + u_a*(-0.016224489)",
|
||||
"lambda_format": "PySRFunction(X=>1.88584 + u_a*(-0.016224489))"
|
||||
},
|
||||
{
|
||||
"complexity": 8,
|
||||
"loss": 0.056762762,
|
||||
"equation": "((dCl_tot_dt - Cd_tot) - dCl_err_dt) * -0.44981483",
|
||||
"score": 0.10850737893550855,
|
||||
"sympy_format": "(-Cd_tot - dCl_err_dt + dCl_tot_dt)*(-0.44981483)",
|
||||
"lambda_format": "PySRFunction(X=>(-Cd_tot - dCl_err_dt + dCl_tot_dt)*(-0.44981483))"
|
||||
},
|
||||
{
|
||||
"complexity": 9,
|
||||
"loss": 0.039528407,
|
||||
"equation": "(Cl_err - (u_a * 0.016350273)) + 1.8692697",
|
||||
"score": 0.36186093414770126,
|
||||
"sympy_format": "Cl_err - 0.016350273*u_a + 1.8692697",
|
||||
"lambda_format": "PySRFunction(X=>Cl_err - 0.016350273*u_a + 1.8692697)"
|
||||
},
|
||||
{
|
||||
"complexity": 10,
|
||||
"loss": 0.038722,
|
||||
"equation": "Cl_err + square((u_a * 0.00608778) - 1.3626369)",
|
||||
"score": 0.020611664022151262,
|
||||
"sympy_format": "Cl_err + (u_a*0.00608778 - 1*1.3626369)**2",
|
||||
"lambda_format": "PySRFunction(X=>Cl_err + (u_a*0.00608778 - 1*1.3626369)**2)"
|
||||
},
|
||||
{
|
||||
"complexity": 11,
|
||||
"loss": 0.03458842,
|
||||
"equation": "Cd_err + (Cl_err + ((u_a * -0.014238624) - -2.0921295))",
|
||||
"score": 0.11288897000276664,
|
||||
"sympy_format": "Cd_err + Cl_err + u_a*(-0.014238624) - 1*(-2.0921295)",
|
||||
"lambda_format": "PySRFunction(X=>Cd_err + Cl_err + u_a*(-0.014238624) - 1*(-2.0921295))"
|
||||
},
|
||||
{
|
||||
"complexity": 12,
|
||||
"loss": 0.031432744,
|
||||
"equation": "(((u_a * -0.015429008) - -1.9807403) - square(Cd_err)) + Cl_err",
|
||||
"score": 0.09566879184310657,
|
||||
"sympy_format": "-Cd_err**2 + Cl_err + u_a*(-0.015429008) - 1*(-1.9807403)",
|
||||
"lambda_format": "PySRFunction(X=>-Cd_err**2 + Cl_err + u_a*(-0.015429008) - 1*(-1.9807403))"
|
||||
},
|
||||
{
|
||||
"complexity": 13,
|
||||
"loss": 0.030870467,
|
||||
"equation": "(Cl_err + square((u_a * 0.0055642533) - 1.4036555)) - square(Cd_err)",
|
||||
"score": 0.01805018576551437,
|
||||
"sympy_format": "-Cd_err**2 + Cl_err + (u_a*0.0055642533 - 1*1.4036555)**2",
|
||||
"lambda_format": "PySRFunction(X=>-Cd_err**2 + Cl_err + (u_a*0.0055642533 - 1*1.4036555)**2)"
|
||||
},
|
||||
{
|
||||
"complexity": 14,
|
||||
"loss": 0.021888444,
|
||||
"equation": "((Cl_err + (Cd_err * 0.5409948)) + (u_a * -0.015207872)) + 1.9898309",
|
||||
"score": 0.3438411400334662,
|
||||
"sympy_format": "Cd_err*0.5409948 + Cl_err + u_a*(-0.015207872) + 1.9898309",
|
||||
"lambda_format": "PySRFunction(X=>Cd_err*0.5409948 + Cl_err + u_a*(-0.015207872) + 1.9898309)"
|
||||
}
|
||||
],
|
||||
"best_sympy": "Cd_err*0.5409948 + Cl_err + u_a*(-0.015207872) + 1.9898309",
|
||||
"best_score": 0.8559884564869915
|
||||
}
|
||||