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
76 changes: 76 additions & 0 deletions case/plume/plume_cylinder_sweep/config.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Cylinder-target SWEEP smoke case: the plate-sweep setup re-aimed at a
# CYLINDER target (data/stl/cylinder_transformed.stl -- radius 2 m, axis along
# X in [-7, 0], centroid (-3.5, 0, 0)). The VV (single argon thruster, D = 1 m,
# S0 = 2.0, Simplified kinetics + Maxwellian wall) is swept over 19 approach
# angles x 5 orbit radii (95 firings; jfh_cylinder_sweep.A) about the cylinder
# centroid, writing per-firing strikes to results/strikes/firing-<i>.vtu. This
# case exists to confirm the strike pipeline RUNS on a curved/closed target;
# the strike results are not physically meaningful. Geometry: the target is
# the shared high-res mesh data/stl/cylinder.stl (14036 faces; resolved from
# the shared data/ dir, not copied into the case per the repo's de-dup
# convention); the sweep JFH is generated by
# jfh/generate_cylinder_sweep_jfh.py (its centroid/radii are unchanged --
# cylinder.stl and cylinder_transformed.stl share the same geometry).

# Visiting Vehicle for RPOD analysis
[vv]
stl_lm = cylinder.stl
stl_thruster = mold_funnel_transformed.stl

# Target Vehicle for RPOD analysis
[tv]
stl = cylinder.stl

# surface wall temperature (Kelvin): Tw/T0 = 1.5 (paper Figs. 17-21)
surface_temp = 300

# proportion of diffuse particle reflections [0, 1]
sigma = 1

# check plume constraints? 0 or 1
check_constraints = 0

# max heat flux integral (J/m^2)
heat_flux_load = inf
heat_flux_window_size = 1

# max heat flux rate (W/m^2)
heat_flux = inf

# max pressure load
normal_pressure_load = inf
normal_pressure_window_size = inf

# max normal pressure (N/m^2)
normal_pressure = inf

# max shear pressure (N/m^2)
shear_pressure = inf

# Plume kinetics and interactions models
[pm]
# Gas kinetics model
kinetics = Simplified

# Gas-surface interaction model
surface_interaction = Maxwellian

# Jet Firing History
[jfh]
jfh = jfh_cylinder_sweep.A

# Thruster configuration data.
[tcd]
# Thruster Configuration File - single head-on thruster, no cant.
tcf = tcf_1_argon.txt

# Thruster Definition File - argon at the paper conditions.
tdf = tdf.csv

# Parameters for scaling plume geometry.
[plume]
radius = 25
# ~89 deg: the default 0.436 (25 deg) would clip the plate -- its lower
# corners sit ~70 deg off-axis at the paper distance. 1.55 rad keeps the
# gating wedge clear of the whole plate at every sweep pose.
wedge_theta = 1.55
75 changes: 75 additions & 0 deletions case/plume/plume_cylinder_sweep/jfh/generate_cylinder_sweep_jfh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""Generate the sweep JFH for the cylinder-target smoke case.

Same angle x distance sweep idea as the plate cases, but aimed at a CYLINDER
target (data/stl/cylinder_transformed.stl: radius 2 m, axis along X spanning
x in [-7, 0], centroid C = (-3.5, 0, 0), bounding-sphere radius ~4.03 m).

The plate is replaced by the cylinder; the visiting vehicle (single thruster
at the VV origin, no cant) is still swept. For each firing the VV is placed on
the arc of radius L about the cylinder centroid C, with the thruster axis aimed
at C and the JFH DCM set so the pipeline's plume normal (first column of the
DCM, with the identity TCF) points along that axis:

d_hat(alpha) = cos(alpha) * n_hat + sin(alpha) * t_hat
VV position = C + L * d_hat(alpha), thruster axis = -d_hat(alpha)

with n_hat = (0, 0, 1) and t_hat = (1, 0, 0), so the sweep orbits the cylinder
in the global X-Z plane (alpha = 0 fires straight down -Z onto the curved
surface; alpha = +/-90 fires along -/+X at the end caps).

The orbit radii all exceed the cylinder's bounding sphere so the VV never sits
inside the target (this case is a pipeline smoke test -- the strike results are
not physically meaningful). Sweep: alpha from -90 to +90 deg in 10 deg steps
(19 angles) x L in {6, 8, 10, 12, 14} m, enumerated distance-major:
firing index = i_L * 19 + i_alpha + 1. 95 firings total, 1.0 s each.

JFH files are always generated by script, never hand-edited. Run from this
directory: python generate_cylinder_sweep_jfh.py
"""

from pathlib import Path

import numpy as np

from generate_jfh_inclined_plate import write_jfh

OUT_NAME = 'jfh_cylinder_sweep.A'

CYLINDER_CENTER = np.array([-3.5, 0.0, 0.0])
ALPHA0_DEG = 0.0 # global-frame orbit-plane tilt
ALPHAS_DEG = np.arange(-90.0, 90.0 + 1e-9, 10.0)
RADII = [6.0, 8.0, 10.0, 12.0, 14.0] # arc radii (m); all > ~4.03 bounding sphere


def pose_for(alpha_deg, L):
"""(vv_position, dcm) for one sweep firing; dcm's first column is the
thruster axis (see the pipeline's plume-normal convention)."""
a0 = np.deg2rad(ALPHA0_DEG)
n_hat = np.array([-np.sin(a0), 0.0, np.cos(a0)])
t_hat = np.array([np.cos(a0), 0.0, np.sin(a0)])
alpha = np.deg2rad(alpha_deg)
d_hat = np.cos(alpha) * n_hat + np.sin(alpha) * t_hat
position = CYLINDER_CENTER + L * d_hat
axis = -d_hat # aimed at the cylinder centroid
# right-handed triad; the axis always lies in the X-Z plane, so the
# global Y axis is a valid second column
c1 = np.array([0.0, 1.0, 0.0])
c2 = np.cross(axis, c1)
dcm = np.column_stack([axis, c1, c2])
return position, dcm


def dcm_string(dcm):
return ' '.join(f'{v:.6e}' for v in np.asarray(dcm).ravel())


if __name__ == '__main__':
firings = []
for L in RADII:
for alpha_deg in ALPHAS_DEG:
position, dcm = pose_for(alpha_deg, L)
firings.append((0.0, 1.0, dcm_string(dcm), tuple(position), [1]))
out_path = Path(__file__).resolve().parent / OUT_NAME
write_jfh(out_path, firings)
print(f'saved {out_path} ({len(firings)} firings: '
f'{len(ALPHAS_DEG)} angles x {len(RADII)} radii)')
37 changes: 37 additions & 0 deletions case/plume/plume_cylinder_sweep/jfh/generate_jfh_inclined_plate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Generate the single-firing JFH for the Cai 2016 inclined-plate case.

One firing at the paper geometry (Aerospace 2016, 3(4):43, Section 4): the
visiting vehicle sits at the origin with an identity DCM, so its single
thruster (exit at the VV origin, no cant) fires along +X toward the plate
centered at (4, 0, 0) m. Firing time 1.0 s makes heat_flux_load equal the
heat-flux rate.

JFH files are always generated by script, never hand-edited. Run from this
directory: python generate_jfh_inclined_plate.py
"""

from pathlib import Path

OUT_NAME = 'jfh_plume_inclined_plate.A'

DCM_IDENTITY = ('1.000000e+00 0.000000e+00 0.000000e+00 '
'0.000000e+00 1.000000e+00 0.000000e+00 '
'0.000000e+00 0.000000e+00 1.000000e+00')


def write_jfh(path, firings):
"""firings: list of (dt, t, dcm_str, xyz, thrusters)."""
lines = [f'offseted {len(firings)} 0', ' 0.000 0.000 0.000']
for n, (dt, t, dcm, xyz, thrusters) in enumerate(firings, start=1):
xyz_str = ' '.join(f'{v:.9g}' for v in xyz)
thr_str = ' '.join(str(i) for i in thrusters)
lines.append(f' {n} {dt:g} {t:g} 0 {dcm} {xyz_str} 1 '
f'{len(thrusters)} {thr_str}')
with open(path, 'w', newline='\n') as fh:
fh.write('\n'.join(lines) + '\n')


if __name__ == '__main__':
out_path = Path(__file__).resolve().parent / OUT_NAME
write_jfh(out_path, [(0.0, 1.0, DCM_IDENTITY, (0.0, 0.0, 0.0), [1])])
print(f'saved {out_path}')
Loading
Loading