pub struct ShockExpansionBody { /* private fields */ }Expand description
A body of revolution laid out for the second-order shock-expansion method: its segments and
the straight elements of its tangent body. A pointed nose’s elements are laid out once; a blunt
tip’s start at a handover that moves with the Mach number (crate::blunt_tip), so they are
laid out at each.
Implementations§
Source§impl ShockExpansionBody
impl ShockExpansionBody
Sourcepub fn new(
segments: &[BodySegment],
elements_per_curve: usize,
) -> Result<Self, AeroError>
pub fn new( segments: &[BodySegment], elements_per_curve: usize, ) -> Result<Self, AeroError>
Lays out a body from its segments, nose first: a curved segment gets
elements_per_curve equal steps in x (tangent at both ends and between), a straight
one a single element. Behind a blunt tip the steps are counted from the handover aft, laid
out at each Mach number (crate::blunt_tip); the segments its cap covers get none.
§Errors
AeroError::Unsupportedif the first segment doesn’t close to a point at its front (pointed, or blunt with a vertical tip), a spherical cap isn’t the first segment, the radius steps between segments (by more than a millionth of it), the radius falls to zero anywhere but the tip, or, for a pointed nose, the tangent lines of consecutive elements don’t meet in order along the body (a profile the tangent body can’t follow).AeroError::Domainfor no segments, elements per curve outside1..=MAX_ELEMENTS_PER_CURVE, a negative or non-finite cylinder dimension, or a spherical cap whose radius isn’t finite and positive or whose length isn’t in(0, radius].
Sourcepub fn with_handover_start(self, start: HandoverStart) -> Self
pub fn with_handover_start(self, start: HandoverStart) -> Self
This body with its march behind a blunt tip’s cap starting from start; a pointed body
is unchanged.
Sourcepub fn with_handover_cap_rad(self, cap_rad: f64) -> Self
pub fn with_handover_cap_rad(self, cap_rad: f64) -> Self
This body with its blunt tip handing over no steeper than cap_rad instead of the flown
crate::blunt_tip::MAX_HANDOVER_RAD; a pointed body is unchanged. A steeper cap follows
TN D-4865’s own rule to a higher Mach number and starts the march from a steeper cone;
what each is worth is measured in ADR-043.
The cap is checked when the handover is taken (Self::handover_m), which refuses one
outside (0, crate::blunt_tip::CONE_TABLE_CAP_RAD]. A pointed body has no handover,
so it ignores the cap and never reports a bad one.
use hpr_aero::blunt_tip::CONE_TABLE_CAP_RAD;
use hpr_aero::shock_expansion::{BodySegment, DEFAULT_ELEMENTS_PER_CURVE, ShockExpansionBody};
use hpr_design::{NoseShape, Profile};
let nose = BodySegment::Profile {
profile: Profile::nose(NoseShape::PowerSeries { exponent: 0.5 }, 0.5, 0.05)?,
};
let body = ShockExpansionBody::new(&[nose], DEFAULT_ELEMENTS_PER_CURVE)?;
// At Mach 3 the wedge detaches past either cap, so each hands over at its own slope, and
// the steeper one leaves the shorter cap. This nose is r = R√(x/L), whose slope is
// R/(2√(xL)), so the handover sits at x = (R/(2 tan δ))²/L: 6.31 mm of nose at 24°,
// 3.75 mm at 30°.
let station = |degrees: f64| (0.05 / (2.0 * degrees.to_radians().tan())).powi(2) / 0.5;
let flown = body.handover_m(3.0)?.expect("a vertical tip hands over");
let steeper = body
.clone()
.with_handover_cap_rad(CONE_TABLE_CAP_RAD)
.handover_m(3.0)?
.expect("a vertical tip hands over");
assert!((flown - station(24.0)).abs() < 1e-9 && (flown - 0.006_31).abs() < 5e-6);
assert!((steeper - station(30.0)).abs() < 1e-9 && (steeper - 0.003_75).abs() < 5e-6);Sourcepub fn vertex_angle_rad(&self) -> f64
pub fn vertex_angle_rad(&self) -> f64
The tip’s half-angle, rad: π/2 for a blunt or vertical tip.
Sourcepub fn has_blunt_tip(&self) -> bool
pub fn has_blunt_tip(&self) -> bool
Whether the tip is blunt or vertical, so the body flies TN D-4865’s Newtonian cap ahead of
the method (crate::blunt_tip).
Sourcepub fn handover_m(&self, mach: f64) -> Result<Option<f64>, AeroError>
pub fn handover_m(&self, mach: f64) -> Result<Option<f64>, AeroError>
Where a blunt tip’s cap hands over to the method at Mach mach, m aft of the vertex:
where the body’s slope first falls to crate::blunt_tip::handover_angle_rad, or to the
body’s own cap (Self::with_handover_cap_rad). None for a pointed tip.
§Errors
AeroError::Domainfor a Mach number that isn’t finite and above 1, or a handover cap outside(0,crate::blunt_tip::CONE_TABLE_CAP_RAD].AeroError::Unsupportedif the body is steeper than the handover’s slope all the way to its end.
Sourcepub fn slope(
&self,
mach: f64,
reference_area_m2: f64,
) -> Result<ShockExpansionSlope, AeroError>
pub fn slope( &self, mach: f64, reference_area_m2: f64, ) -> Result<ShockExpansionSlope, AeroError>
C_Nα (per radian, on reference_area_m2) and the center of pressure at Mach mach, by
TN 3527’s multi-step method.
§Errors
AeroError::Domainfor a Mach number that isn’t above 1, or a reference area that isn’t positive.AeroError::Unsupportedwhere the method doesn’t hold: a tip cone whose shock detaches, a tangent cone steeper than the cone tables’ 30°, a corner the flow can’t turn supersonically, a tip cone whose surface flow is subsonic, a cylinder’s or a boattail’s element whose pressure moves away from the one it relaxes toward (the free stream’s and footnote 8’s; neither is a tangent cone of that element’s own flow, so the reduction offlare_reduction_turns_radis not read there), or a lift that doesn’t sum to a positive force; and for a blunt tip, whose elements are laid out at each Mach number, a nose steeper than the handover’s slope all the way to its end, or a tangent body whose elements don’t meet in order behind the handover (asSelf::newsays for a pointed one).
The report states the method for Mach number over nose fineness from 0.4 to 2 (Summary,
p. 1); slope doesn’t enforce that range, and its own Mach 6.28 rows are at 2.09.
Sourcepub fn segment_slopes(
&self,
mach: f64,
reference_area_m2: f64,
) -> Result<Vec<SegmentSlope>, AeroError>
pub fn segment_slopes( &self, mach: f64, reference_area_m2: f64, ) -> Result<Vec<SegmentSlope>, AeroError>
Each segment’s share of Self::slope, in the order of the segments: its C_Nα (per
radian, on reference_area_m2) and that slope’s moment about the vertex. The shares sum
to the whole body’s slope and moment up to rounding: every segment’s start is a break of
the integral, so each piece of it lies inside one segment.
§Errors
As Self::slope.
Sourcepub fn element_flows(
&self,
mach: f64,
) -> Result<Vec<ElementFlowReport>, AeroError>
pub fn element_flows( &self, mach: f64, ) -> Result<Vec<ElementFlowReport>, AeroError>
The flow the method computes on each element of the tangent body at Mach mach, in order
from the vertex or a blunt tip’s handover: what a hand calculation of eq. 19,
C_Nα = (2π/A_ref) ∫ Λ r dx, needs. Behind a blunt tip the list starts at the handover
(Self::handover_m), and the lift of the Newtonian cap ahead of it is not in the list.
§Errors
As Self::slope, less the check that the lift sums to a positive force.
Sourcepub fn aft_flow(&self, mach: f64) -> Result<AftFlow, AeroError>
pub fn aft_flow(&self, mach: f64) -> Result<AftFlow, AeroError>
The surface flow the march delivers to the body’s aft end at Mach mach: everything a
corner behind the body needs: the surface Mach number and angle there, the pressure, the
gradient the last element carries to it, the radius, and the free stream’s Mach number.
The angle is the last element’s, so on a body that ends in a curve it is that element’s
chord rather than the tangent at the very end, and it moves a little with
elements_per_curve. On a body that ends in a cylinder or a cone, which is every body a
flare joins in a flight today, the two are the same.
This is the flow a corner behind the body turns. The march is downstream-only: TN 3527
eq. 3 fixes each element from the one ahead of it and nothing behind, so a flare added at
the aft end cannot change it, and the limit on that flare’s corner
(flare_corner_limit_rad) can be read from this body before the flare is drawn.
§Errors
As Self::slope, less the check that the lift sums to a positive force, and
AeroError::Unsupported where the surface flow at the aft end is not supersonic.
Sourcepub fn reduced_elements(&self, mach: f64) -> Result<usize, AeroError>
pub fn reduced_elements(&self, mach: f64) -> Result<usize, AeroError>
How many of the body’s elements the march reduces to the generalized method at Mach
mach: those where the gradient behind the corner points away from the tangent cone’s
pressure (η < 0, TN 3527 p. 13), which carry no gradient on (see
issue #81). Zero means the result doesn’t
depend on that reading.
Which turns a corner reduces is a property of its own state, and
flare_reduction_turns_rad solves for the two that bound them.
§Errors
AeroError::Domainfor a Mach number that isn’t finite and above 1.AeroError::Unsupportedwhere the march fails, as forSelf::slope: a detached tip shock, a tangent cone past the cone tables’ 30°, a corner the flow can’t turn, subsonic surface flow, or a cylinder’s or boattail’s element that would be reduced. AnOkcount doesn’t promise thatSelf::slopesucceeds: it also needs a positive total lift.
Sourcepub fn tangent_cone_crossings(&self, mach: f64) -> Result<usize, AeroError>
pub fn tangent_cone_crossings(&self, mach: f64) -> Result<usize, AeroError>
How many times the marched surface pressure crosses its own tangent cone’s at Mach mach:
the number of elements whose gap p_c − p₂ has the opposite sign to the last element that
had one, counting only pairs within one segment of the body. A pair that straddles a
segment’s start does not count: there p_c itself steps (from a cone’s pressure to the
free stream’s where a nose meets a cylinder, to footnote 8’s where a boattail begins, or
to a steeper cone’s where a flare does), so the gap changes sign without ever passing
through zero, and there is no pole. Within a segment the profile is continuous, so p_c
is too, and a sign change means the gap really closed.
A crossing is what marks an answer that moves with the element count. Along an element
the method
relaxes the pressure and the loading toward the tangent cone’s as e^(−η) with
η = k (x − x₂) (eqs. 8, 9 and 19), where the rate per unit length is
k = (∂p/∂s)₂ / ((p_c − p₂) cos δ₂). Where the pressure crosses its tangent cone’s the gap
passes through zero while the gradient does not, so k has a pole. The pressure itself
rides through it (k (p_c − p) cos δ₂ is just the gradient, which stays finite), but the
loading borrows the pressure’s k (eq. 19) while its own gap Λ_c − Λ does not close
with it, so the loading is driven onto the tangent cone’s arbitrarily fast. A march applies
k from the corner over a whole element, so how much of that lands depends on where the
crossing falls between corners, and the answer follows the element count instead of
settling.
It is a flag, not a verdict, at either end. A count of zero does not promise an answer settled: whether a crossing is seen depends on the mesh, and the count is not even monotone in it: readings that cross at 40 and 160 elements per curve can show none at 10. Nor does a count above zero promise the answer never settles: one reading of hpr’s own sweep crosses at every mesh and still holds to 0.003 per radian from 60 elements on. What is measured is that over 10, 40 and 160 elements the crossings, and only the crossings, mark the readings that move (ADR-044). Nothing in a flight calls this: it is a tool for studying a body, not a guard.
The fineness-3 ogive TN 3527 prints values for never crosses at the Mach numbers hpr can
check it at; there η < 0 comes from the gradient changing sign with the gap all one way,
which is bounded and settles. So this count, not Self::reduced_elements, is the one to
read when an answer moves with the element count; see
issue #108.
An element whose gap is exactly zero is skipped rather than given a sign: behind a blunt
tip the march starts on its own tangent cone under the default
HandoverStart::TangentCone, and that element has no side to be on. Under
HandoverStart::Newtonian it does, because its pressure and its tangent cone’s come
from different models, and the count then includes that mismatch.
§Errors
Trait Implementations§
Source§impl Clone for ShockExpansionBody
impl Clone for ShockExpansionBody
Source§fn clone(&self) -> ShockExpansionBody
fn clone(&self) -> ShockExpansionBody
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for ShockExpansionBody
impl Debug for ShockExpansionBody
Source§impl PartialEq for ShockExpansionBody
impl PartialEq for ShockExpansionBody
Source§fn eq(&self, other: &ShockExpansionBody) -> bool
fn eq(&self, other: &ShockExpansionBody) -> bool
self and other values to be equal, and is used by ==.