diff --git a/README.md b/README.md index b9673cc..60597e2 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,9 @@ Reproduce all figures from committed CSVs (no solver needed): python3 scripts/three_regime_comparison.py --plot-only ``` +- Plant-validation foundation: [`docs/freedecay_validation.md`](docs/freedecay_validation.md) +- Simulation-data regeneration index: [`docs/REPRODUCTION.md`](docs/REPRODUCTION.md) + ## Repository structure ``` diff --git a/analysis/FINDINGS_3REGIME.md b/analysis/FINDINGS_3REGIME.md index 08a484c..4654d2f 100644 --- a/analysis/FINDINGS_3REGIME.md +++ b/analysis/FINDINGS_3REGIME.md @@ -10,6 +10,12 @@ Controller co-design study across VGOSWEC flap variants (VGM-0/10/20/45/90) over All results are reproducible from committed CSVs under `analysis/{cc,opt_passive,passive_guarded}/` via `--plot-only`. No solver runs required. +> **Validated-plant foundation:** The controller/flap co-design results below +> rest on the free-decay WEC-Sim plant validation in +> [`../docs/freedecay_validation.md`](../docs/freedecay_validation.md), which +> verifies both the reactive plant impedance (**ω_n**) and the resistive +> radiation-damping response (**ζ / B55**) across VGM-0/10/20/45/90. + --- ## 1. Three-regime relay (headline result) diff --git a/docs/REPRODUCTION.md b/docs/REPRODUCTION.md new file mode 100644 index 0000000..b0daa23 --- /dev/null +++ b/docs/REPRODUCTION.md @@ -0,0 +1,191 @@ +# Simulation reproduction index + +This repository contains the full command chain needed to regenerate the +simulation-side datasets used in the VGOSWEC study. With the commands below, +the simulation results, summary CSVs, and figures are reproducible from this +repo alone; subsequent work can therefore be research/writing rather than +pipeline reconstruction. + +## Solver prerequisite for `--run` / sweep commands + +Any command below that launches `build/demo_vgoswec` requires the documented +SEA-Stack / Chrono build first: + +```bash +source scripts/setup_env.sh +cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}" +cmake --build build -j$(nproc) +``` + +This produces `build/demo_vgoswec`. Headless workflows use `--no-viz`, so the +optional GUI / VSG stack is not required for CSV-only reproduction. + +## Reproduction modes + +- **Solver-invoking path**: the initial sweep or `--run` path calls + `build/demo_vgoswec` and regenerates raw simulation outputs. +- **`--plot-only` path**: regenerates figures from committed CSVs **without** + calling the solver. + +## 1. Free-decay validation foundation + +**Purpose:** regenerate the plant-validation basis used by the controller study. + +```bash +# Clean-checkout, fully self-contained path: re-run the five free-decay cases, +# re-analyze ζ, then refresh the ω_n summary CSV/figure. +python3 scripts/freedecay_validation.py --run --make-figures +python3 scripts/plot_freedecay_validation.py + +# If output/vgoswec_*_freedecay_results.csv already exist locally, reuse them: +python3 scripts/freedecay_validation.py --make-figures +python3 scripts/plot_freedecay_validation.py +``` + +- **Solver behavior** + - `scripts/freedecay_validation.py --run --make-figures` invokes + `build/demo_vgoswec` internally for + `config/vgoswec_{0,10,20,45,90}_freedecay.yaml`. + - The companion `scripts/plot_freedecay_validation.py` does **not** invoke + the solver; it reuses `output/vgoswec_*_freedecay_results.csv` if present. +- **Inputs consumed** + - Solver configs: `config/vgoswec_{0,10,20,45,90}_freedecay.yaml` + - Shared analysis helpers: `scripts/freedecay_analysis.py` + - Raw solver outputs: `output/vgoswec_*_freedecay_results.csv` +- **Outputs produced** + - `output/vgoswec_{0,10,20,45,90}_freedecay_results.csv` + - `docs/freedecay_validation.csv` + - `docs/img/freedecay_validation.png` + - `docs/img/freedecay_zeta_validation.png` + - `docs/img/freedecay_zeta_decay_fit.png` + +See also: [`docs/freedecay_validation.md`](freedecay_validation.md). + +## 2. CC capture-efficiency sweep + +```bash +# Re-run the CC sweep (invokes build/demo_vgoswec): +python3 scripts/cc_capture_efficiency_sweep.py + +# Reuse committed CSVs and regenerate figures only: +python3 scripts/cc_capture_efficiency_sweep.py --plot-only +``` + +- **Solver behavior** + - Default invocation runs the sweep across the shared `T = 0.5–7.0 s` grid + using `build/demo_vgoswec`. + - `--plot-only` reuses committed CSVs and does not call the solver. +- **Inputs consumed** + - Solver configs: `config/vgoswec_{0,10,20,45,90}_cc.yaml` + - Hydro inputs: `hydroData/vgoswec_{0,10,20,45,90}.h5` + - `--plot-only` inputs: `analysis/cc/capture_efficiency_VGM{0,10,20,45,90}.csv` +- **Outputs produced** + - `analysis/cc/capture_efficiency_VGM{0,10,20,45,90}.csv` + - `analysis/cc/figures/capture_efficiency_VGM{0,10,20,45,90}.png` + - `analysis/cc/figures/power_breakdown_VGM{0,10,20,45,90}.png` + - `analysis/cc/figures/capture_efficiency_summary.png` + +## 3. ff+PID (`passive_guarded`) capture-efficiency sweep + +```bash +# Re-run the tuned exc_ff_pid sweep (invokes build/demo_vgoswec): +python3 scripts/capture_efficiency_sweep.py + +# Reuse committed CSVs and regenerate figures only: +python3 scripts/capture_efficiency_sweep.py --plot-only +``` + +- **Solver behavior** + - Default invocation runs the sweep across the shared `T = 0.5–7.0 s` grid + using `build/demo_vgoswec`. + - `--plot-only` reuses committed CSVs and does not call the solver. +- **Inputs consumed** + - Solver configs: `config/vgoswec_{0,10,20,45,90}_exc_ff_pid.yaml` + - Hydro inputs: `hydroData/vgoswec_{0,10,20,45,90}.h5` + - `--plot-only` inputs: + `analysis/passive_guarded/capture_efficiency_VGM{0,10,20,45,90}.csv` +- **Outputs produced** + - `analysis/passive_guarded/capture_efficiency_VGM{0,10,20,45,90}.csv` + - `analysis/passive_guarded/figures/capture_efficiency_VGM{0,10,20,45,90}.png` + - `analysis/passive_guarded/figures/capture_efficiency_summary.png` + +## 4. opt_passive sweep + +```bash +# Re-run the passive + opt_passive sweep (invokes build/demo_vgoswec): +python3 scripts/passive_vs_optpassive_sweep.py + +# Reuse committed CSVs and regenerate figures only: +python3 scripts/passive_vs_optpassive_sweep.py --plot-only +``` + +- **Solver behavior** + - Default invocation runs both the `passive` and `opt_passive` arms across the + shared `T = 0.5–7.0 s` grid using `build/demo_vgoswec`. + - `--plot-only` reuses committed CSVs and does not call the solver. +- **Inputs consumed** + - Solver configs: + `config/vgoswec_{0,10,20,45,90}_passive.yaml`, + `config/vgoswec_{0,10,20,45,90}_opt_passive.yaml` + - Hydro inputs: `hydroData/vgoswec_{0,10,20,45,90}.h5` + - `--plot-only` inputs: + `analysis/passive/capture_efficiency_VGM{0,10,20,45,90}.csv`, + `analysis/opt_passive/capture_efficiency_VGM{0,10,20,45,90}.csv` +- **Outputs produced** + - `analysis/passive/capture_efficiency_VGM{0,10,20,45,90}.csv` + - `analysis/opt_passive/capture_efficiency_VGM{0,10,20,45,90}.csv` + - `analysis/passive/figures/capture_efficiency_VGM{0,10,20,45,90}.png` + - `analysis/opt_passive/figures/capture_efficiency_VGM{0,10,20,45,90}.png` + - `analysis/passive/figures/capture_efficiency_summary.png` + - `analysis/opt_passive/figures/capture_efficiency_summary.png` + - `analysis/passive_vs_optpassive/figures/` + +## 5. CC vs ff+PID comparison + +```bash +python3 scripts/cc_vs_ffpid_comparison.py --plot-only +``` + +- **Solver behavior** + - This is an analysis-only overlay script; it consumes existing sweep CSVs and + does not invoke `build/demo_vgoswec`. +- **Inputs consumed** + - `analysis/cc/capture_efficiency_VGM{0,10,20,45,90}.csv` + - `analysis/passive_guarded/capture_efficiency_VGM{0,10,20,45,90}.csv` +- **Outputs produced** + - `analysis/comparison/figures/cc_vs_ffpid_VGM{0,10,20,45,90}.png` + - `analysis/comparison/figures/cc_vs_ffpid_efficiency_VGM{0,10,20,45,90}.png` + - `analysis/comparison/figures/cc_vs_ffpid_summary.png` + - `analysis/comparison/figures/cc_vs_ffpid_efficiency_summary.png` + +## 6. Three-regime relay + operating envelopes + +```bash +python3 scripts/three_regime_comparison.py --plot-only +``` + +- **Solver behavior** + - This is an analysis-only summary script; it consumes existing sweep CSVs and + does not invoke `build/demo_vgoswec`. +- **Inputs consumed** + - `analysis/cc/capture_efficiency_VGM{0,10,20,45,90}.csv` + - `analysis/opt_passive/capture_efficiency_VGM{0,10,20,45,90}.csv` + - `analysis/passive_guarded/capture_efficiency_VGM{0,10,20,45,90}.csv` +- **Outputs produced** + - `analysis/three_regime/figures/three_regime_VGM{0,10,20,45,90}.png` + - `analysis/three_regime/figures/three_regime_efficiency_VGM{0,10,20,45,90}.png` + - `analysis/three_regime/figures/three_regime_summary.png` + - `analysis/three_regime/figures/three_regime_efficiency_summary.png` + - `analysis/three_regime/figures/operating_envelope.png` + - `analysis/three_regime/figures/operating_envelope_efficiency.png` + - `analysis/three_regime/operating_envelope.csv` + - `analysis/three_regime/operating_envelope_efficiency.csv` + +## Bottom line + +Only the initial sweep / `--run` commands invoke `build/demo_vgoswec`. All +`--plot-only` paths regenerate figures from committed CSVs **without** the +solver. Together, these commands make the entire simulation side reproducible +from this repo alone. diff --git a/docs/freedecay_validation.md b/docs/freedecay_validation.md index b76a5e7..7a35b88 100644 --- a/docs/freedecay_validation.md +++ b/docs/freedecay_validation.md @@ -1,5 +1,23 @@ # Free-decay validation of the C++ VGOSWEC model against Husain et al. (Ogden et al., ASME JOMAE 145(3):030905), Table 2 and Fig. 4 +## Foundation: plant validation against WEC-Sim + +This validation is the **foundation** on which the three-regime controller/flap +co-design study rests. The co-design results are only meaningful because the +plant's **reactive impedance** (natural frequency **ω_n**) and **resistive +impedance** (damping ratio **ζ**, i.e. radiation damping **B55**) are +WEC-Sim-validated across the full **0°–90°** VGOSWEC geometric sweep +(VGM-0/10/20/45/90). + +## Validation → Study bridge + +The free-decay match is the bridge from plant model to controller study: +validating **ω_n** confirms the reactive impedance (**A55**-driven added +inertia plus hinge stiffness) that the **CC** and **opt_passive** +impedance-matching arguments depend on, while validating **ζ / B55** confirms +the radiation damping that sets **P_opt** and therefore the entire +capture-efficiency denominator used throughout the three-regime analysis. + ## Purpose This validation demonstrates that spring-only free-decay simulations in the C++ VGOSWEC model recover both the natural frequency **ω_n** and the damping ratio **ζ** for each available geometry, and match the values reported in Husain et al. / Ogden et al. (ASME JOMAE 145(3):030905) — Table 2 for ω_n, and Fig. 4 for ζ. @@ -161,23 +179,79 @@ The numerical-dissipation component is minor (≈4×10⁻⁴, or ~8%) and conver --- -## Reproduction +## Full reproduction from a clean checkout -Run free-decay cases and regenerate all figures and the validation CSV: +The free-decay validation is reproducible end-to-end from this repository alone +as the following numbered pipeline: -```bash -# Optionally re-run simulations (requires built binary): -# python3 scripts/freedecay_validation.py --run --make-figures +1. **Build the SEA-Stack / Chrono binary** -# Reuse existing output CSVs (default): -python3 scripts/freedecay_validation.py --make-figures -``` + ```bash + source scripts/setup_env.sh + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}" + cmake --build build -j$(nproc) + ``` + + This produces `build/demo_vgoswec`. The documented prerequisites are + **SEA-Stack**, **Project Chrono**, **yaml-cpp**, and **Eigen3**; the + headless free-decay workflow below uses `--no-viz`, so it does **not** + require the optional GUI / VSG stack. + +2. **Run the raw SEA-Stack free-decay cases** + + ```bash + for deg in 0 10 20 45 90; do + ./build/demo_vgoswec --config config/vgoswec_${deg}_freedecay.yaml --no-viz + done + ``` + + Each case writes `output/vgoswec_${deg}_freedecay_results.csv`. The analysis + consumes the resulting time histories, including `time_s`, + `flap_pitch_rad`, and the other solver-output columns in those CSVs. + +3. **Run the Python free-decay analysis** + + ```bash + # Re-run sims internally AND regenerate the ζ analysis/figures: + python3 scripts/freedecay_validation.py --run --make-figures + + # OR, if output/vgoswec_*_freedecay_results.csv already exist locally, + # reuse them and only re-analyze/re-plot the ζ outputs: + python3 scripts/freedecay_validation.py --make-figures + ``` + + `--run` calls `build/demo_vgoswec` internally for each of the five + `config/vgoswec_{deg}_freedecay.yaml` cases, so step 2 is optional if you + use that flag. The unified driver depends only on **NumPy** (+ **Matplotlib** + when `--make-figures` is used). Shared `load_series`, peak-detection, + log-decrement, and ω_n-estimation helpers live in + `scripts/freedecay_analysis.py`. + +4. **Refresh the ω_n summary CSV / figure** + + ```bash + python3 scripts/plot_freedecay_validation.py + ``` + + This companion ω_n-only plotter writes `docs/freedecay_validation.csv` and + `docs/img/freedecay_validation.png`, using the just-generated + `output/vgoswec_*_freedecay_results.csv` when present and otherwise falling + back to its embedded validated values. + +5. **Resulting artifacts** -The unified validation script (`scripts/freedecay_validation.py`) computes both ω_n (FFT + zero-cross) and ζ (logdec with correct n), prints the comparison table, writes `docs/freedecay_validation.csv`, and regenerates the ζ figures. It depends only on NumPy (+ optional Matplotlib for figures). + This pipeline regenerates the free-decay validation artifacts in order: -The ω_n-only plotting script is at `scripts/plot_freedecay_validation.py` (unchanged external behavior/outputs). + - `build/demo_vgoswec` + - `output/vgoswec_{0,10,20,45,90}_freedecay_results.csv` + - `docs/img/freedecay_zeta_validation.png` + - `docs/img/freedecay_zeta_decay_fit.png` + - `docs/freedecay_validation.csv` + - `docs/img/freedecay_validation.png` -Shared analysis functions (load_series, peak detection, logdec, ω_n estimation) are in `scripts/freedecay_analysis.py`. +The ω_n-only plotting script is at `scripts/plot_freedecay_validation.py`. Quick Python extraction for ω_n (robust to NaNs, sorted time, and transient removal):