Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,40 @@ PyRPOD utilizies scientific libraries such as NumPy, SciPy, Matplotlib, and SymP
python -m pytest tests/rpod # or just point pytest at a directory/file directly
```

## Plume Validation Trade Studies

Prescribed plume/target validation sweeps (fixed target, engineer-placed
firing poses, swept approach angle and source distance) run through a
package-level API on top of any existing case:

```python
from pyrpod.mdao.TradeStudy import TradeStudy

study = TradeStudy.from_config(
'case/plume/plume_flat_plate_sweep/study/flat_plate_baseline.yaml')
results = study.run() # per-component force, moment, center of
# pressure, peak loads, VTK paths, CSV + JSON
```

A YAML study configuration adds the sweep, the exact JFH firing count, the
moment reference point and the coefficient normalization on top of the case's
own `config.ini`, which keeps owning every asset. `sweep.mode` picks how the
sweep is decomposed — `per_case` gives every angle-distance combination its
own Jet Firing History, `single_jfh` runs the whole sweep as one history with
a single strike series and a sweep-wide load envelope. Results can be compared
against independently generated reference data (DSMC, analytical,
experimental — the interface does not care which) through a generic
comparison layer.

See [docs/plume_validation_study.md](docs/plume_validation_study.md) for the
architecture, the configuration schema, the exact meaning of `n_firings`, the
force / moment / center-of-pressure definitions, the result schema, the
reference-data format, and the known limitations. Worked examples:
[`flat_plate_baseline.yaml`](case/plume/plume_flat_plate_sweep/study/flat_plate_baseline.yaml),
[`flat_plate_sweep.yaml`](case/plume/plume_flat_plate_sweep/study/flat_plate_sweep.yaml)
and its single-history form
[`flat_plate_sweep_single_jfh.yaml`](case/plume/plume_flat_plate_sweep/study/flat_plate_sweep_single_jfh.yaml).

## Test Reporting

Test information lives in two places, and the split is deliberate:
Expand Down
69 changes: 69 additions & 0 deletions case/plume/plume_cylinder_sweep/study/cylinder_baseline.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# PyRPOD prescribed plume-validation study: CYLINDER target, one firing.
#
# The same study machinery as the flat-plate examples, pointed at the curved,
# closed target of case/plume/plume_cylinder_sweep (radius 2 m, axis along X
# spanning x in [-7, 0], centroid (-3.5, 0, 0)). It exists to keep the study
# architecture honest -- nothing in it assumes a flat plate -- and to be the
# place quantitative cylinder reference data plugs into later, through the
# same generic reference-comparison interface the plate cases use.
#
# NOTE: as in the case itself, the cylinder results are a PIPELINE SMOKE
# CASE, not a validated physical answer: no cylinder reference data exists
# yet. No normalization inputs are supplied, so coefficients are correctly
# reported as unavailable rather than invented.

study:
name: cylinder_baseline
description: >-
Single head-on firing against the cylinder target; architecture check and
future home of quantitative cylinder validation.
case_dir: ..
output_dir: ../results/studies/cylinder_baseline

thruster:
id: T1

plume_model:
name: SimplifiedGasKinetics
parameters:
gas: argon
speed_ratio_S0: 2.0
stagnation_temperature_K: 200.0
nozzle_diameter_m: 1.0

target:
geometry_id: cylinder.stl
# Cylinder centroid; the sweep arc is built about it, exactly as the
# case's own jfh/generate_cylinder_sweep_jfh.py does.
reference_point: [-3.5, 0.0, 0.0]
normal: [0.0, 0.0, 1.0]
tangent: [1.0, 0.0, 0.0]
components:
- name: cylinder
selector: all

sweep:
plate_angles_deg: [0.0]
# Orbit radius; larger than the ~4.03 m bounding sphere of the target.
source_distances: [6.0]
n_firings: 1
firing_duration_s: 1.0
thrusters: [1]

loads:
moment_reference_point: [-3.5, 0.0, 0.0]
# No normalization block: coefficients are reported as unavailable.

output:
vtk:
enabled: true
summary:
csv: case_results.csv
metadata: study_metadata.json
plots:
enabled: false

metadata:
coordinate_system: >-
case global frame; cylinder axis along X, plume source swept in the X-Z
plane about the cylinder centroid
86 changes: 86 additions & 0 deletions case/plume/plume_flat_plate_sweep/study/flat_plate_baseline.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# PyRPOD prescribed plume-validation study: flat-plate BASELINE case.
#
# One head-on firing of the Cai 2016 round argon jet (D = 1 m, S0 = 2.0,
# T0 = 200 K, Tw = 300 K, fully diffuse) against the flat 8 m x 8 m plate of
# case/plume/plume_flat_plate_sweep, with the plume source at L = 4D on the
# plate normal. This is the single-pose reference point of the sweep in
# flat_plate_sweep.yaml.
#
# Run it:
# from pyrpod.mdao.TradeStudy import TradeStudy
# results = TradeStudy.from_config(
# 'case/plume/plume_flat_plate_sweep/study/flat_plate_baseline.yaml'
# ).run()
#
# The case's own config.ini still owns every asset (STL, TCF, TDF, plume
# model and gating geometry); this file adds only the study layer.

study:
name: cai2016_flat_plate_baseline
description: >-
Head-on flat-plate plume impingement at L/D = 4, Cai 2016 Section 4
conditions, run through the prescribed trade-study API.
case_dir: ..
output_dir: ../results/studies/flat_plate_baseline

# One thruster, recorded explicitly. It must exist in the case's TCF.
thruster:
id: T1

# The only plume model this workflow supports.
plume_model:
name: SimplifiedGasKinetics
parameters:
# Recorded for provenance; the values themselves are read from the
# case's thruster definition file (tcd/tdf.csv, thruster type ARG).
gas: argon
speed_ratio_S0: 2.0
stagnation_temperature_K: 200.0
nozzle_diameter_m: 1.0

target:
geometry_id: flat_plate_transformed.stl
# Plate center; the sweep arc and the angle convention are built about it.
reference_point: [0.0, 0.0, 0.0]
# Outward normal (toward the plume-source side) and in-plane tilt axis.
normal: [0.0, 0.0, 1.0]
tangent: [1.0, 0.0, 0.0]
components:
- name: plate
selector: all

sweep:
plate_angles_deg: [0.0]
source_distances: [4.0]
# Exactly this many entries are written to the case's Jet Firing History.
n_firings: 1
firing_duration_s: 1.0
thrusters: [1]

loads:
# Moments are reported about this user-defined point (the plate center).
moment_reference_point: [0.0, 0.0, 0.0]
normalization:
# Plate area 8 m x 8 m and semi-length H0 = 4 m.
reference_area: 64.0
reference_length: 4.0
# Cai's normalization, derived from the case's own TDF entry:
# q_dyn = n0*m*U0^2/2 with n0 = 1e20 m^-3, U0 = 577.0684534784414 m/s,
# m = (R_universal / R_specific) / N_A, R_specific = 208.13
# q_heat = n0*m*U0^3/2
dynamic_pressure: 1.1044652197738332
reference_heat_flux: 637.3520362956127

output:
vtk:
enabled: true
summary:
csv: case_results.csv
metadata: study_metadata.json
plots:
enabled: false

metadata:
coordinate_system: >-
case global frame; plate in the X-Y plane centered at the origin,
plume source on the +Z side
76 changes: 76 additions & 0 deletions case/plume/plume_flat_plate_sweep/study/flat_plate_sweep.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# PyRPOD prescribed plume-validation study: flat-plate ANGLE x DISTANCE sweep.
#
# The multi-angle / multi-distance analog of flat_plate_baseline.yaml: the
# stationary 8 m x 8 m plate of case/plume/plume_flat_plate_sweep is struck
# from 19 approach angles (-90 .. +90 deg in 10 deg steps, 0 = head-on) at 5
# stand-off distances (L/D in {2, 4, 6, 8, 10}, D = 1 m) -- 95 cases, one
# firing each, matching the committed sweep JFH of that case.
#
# Run it:
# from pyrpod.mdao.TradeStudy import TradeStudy
# study = TradeStudy.from_config(
# 'case/plume/plume_flat_plate_sweep/study/flat_plate_sweep.yaml')
# results = study.run()
# study.plot() # optional trend figures
#
# Expect ~10368 faces x 95 poses; with VTK output enabled this writes one
# .vtu per case under results/studies/flat_plate_sweep/cases/.

study:
name: cai2016_flat_plate_sweep
description: >-
Flat-plate plume impingement swept over 19 approach angles and 5
stand-off distances, Cai 2016 Section 4 conditions.
case_dir: ..
output_dir: ../results/studies/flat_plate_sweep

thruster:
id: T1

plume_model:
name: SimplifiedGasKinetics
parameters:
gas: argon
speed_ratio_S0: 2.0
stagnation_temperature_K: 200.0
nozzle_diameter_m: 1.0

target:
geometry_id: flat_plate_transformed.stl
reference_point: [0.0, 0.0, 0.0]
normal: [0.0, 0.0, 1.0]
tangent: [1.0, 0.0, 0.0]
components:
- name: plate
selector: all

sweep:
plate_angles_deg: [-90.0, -80.0, -70.0, -60.0, -50.0, -40.0, -30.0, -20.0,
-10.0, 0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0,
80.0, 90.0]
source_distances: [2.0, 4.0, 6.0, 8.0, 10.0]
n_firings: 1
firing_duration_s: 1.0
thrusters: [1]

loads:
moment_reference_point: [0.0, 0.0, 0.0]
normalization:
reference_area: 64.0
reference_length: 4.0
dynamic_pressure: 1.1044652197738332
reference_heat_flux: 637.3520362956127

output:
vtk:
enabled: true
summary:
csv: sweep_results.csv
metadata: sweep_metadata.json
plots:
enabled: true

metadata:
coordinate_system: >-
case global frame; plate in the X-Y plane centered at the origin,
plume source swept in the X-Z plane
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# PyRPOD prescribed plume-validation study: flat-plate sweep as ONE JFH.
#
# Same physics, same poses and same normalization as flat_plate_sweep.yaml --
# 19 approach angles x 5 stand-off distances against the 8 m x 8 m plate of
# case/plume/plume_flat_plate_sweep -- but executed as a SINGLE case driven by
# a SINGLE Jet Firing History holding all 95 firings (sweep.mode: single_jfh).
#
# What that buys, over the per-case form:
# * one strike run, so every firing's results come from the same pipeline
# invocation and the same cumulative accumulation;
# * one results/strikes/firing-<i>.vtu series (i = 0 .. 94) that ParaView
# can scrub as a time sequence, matching the case's own sweep convention;
# * a sweep ENVELOPE in the metadata: per component, the worst pressure and
# shear any pose produced on any face, the accumulated heat-flux load, the
# coverage (unique struck faces / swept affected area).
#
# n_firings stays the count per POSE, so this file and flat_plate_sweep.yaml
# differ only in `mode` and the output names: 19 x 5 poses x 1 firing = a JFH
# of exactly 95 entries.
#
# Run it:
# from pyrpod.mdao.TradeStudy import TradeStudy
# study = TradeStudy.from_config(
# 'case/plume/plume_flat_plate_sweep/study/'
# 'flat_plate_sweep_single_jfh.yaml')
# results = study.run() # -> ParameterSweepStudy
# study.validation_study.envelope['plate']

study:
name: cai2016_flat_plate_sweep_single_jfh
description: >-
Flat-plate plume impingement over 19 approach angles and 5 stand-off
distances, executed as one 95-firing Jet Firing History.
case_dir: ..
output_dir: ../results/studies/flat_plate_sweep_single_jfh

thruster:
id: T1

plume_model:
name: SimplifiedGasKinetics
parameters:
gas: argon
speed_ratio_S0: 2.0
stagnation_temperature_K: 200.0
nozzle_diameter_m: 1.0

target:
geometry_id: flat_plate_transformed.stl
reference_point: [0.0, 0.0, 0.0]
normal: [0.0, 0.0, 1.0]
tangent: [1.0, 0.0, 0.0]
components:
- name: plate
selector: all

sweep:
# One Jet Firing History for the whole sweep.
mode: single_jfh
plate_angles_deg: [-90.0, -80.0, -70.0, -60.0, -50.0, -40.0, -30.0, -20.0,
-10.0, 0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0,
80.0, 90.0]
source_distances: [2.0, 4.0, 6.0, 8.0, 10.0]
# Entries contributed by each pose; the history holds 19 * 5 * 1 = 95.
n_firings: 1
firing_duration_s: 1.0
thrusters: [1]

loads:
moment_reference_point: [0.0, 0.0, 0.0]
normalization:
reference_area: 64.0
reference_length: 4.0
dynamic_pressure: 1.1044652197738332
reference_heat_flux: 637.3520362956127

output:
vtk:
enabled: true
summary:
csv: sweep_results.csv
metadata: sweep_metadata.json
plots:
enabled: true

metadata:
coordinate_system: >-
case global frame; plate in the X-Y plane centered at the origin,
plume source swept in the X-Z plane
Loading
Loading