Skip to main content

AeroModel

Struct AeroModel 

Source
pub struct AeroModel { /* private fields */ }
Expand description

A rocket’s aerodynamic model: normal force, center of pressure and drag.

Serialize-only, for inspection: a model is built from a Layout by AeroModel::new, which checks what it builds.

Implementations§

Source§

impl AeroModel

Source

pub fn new(layout: &Layout) -> Result<Self, AeroError>

Builds the terms of every component of layout, with hpr’s current body model (BodyModel::default).

§Errors

As Self::with_body_model.

Source

pub fn with_body_model( layout: &Layout, body_model: BodyModel, ) -> Result<Self, AeroError>

Builds the terms of every component of layout, its bodies’ lift and supersonic boattails by body_model.

§Errors
  • AeroError::Domain for a non-positive reference diameter, rocket length or body radius.
  • AeroError::InComponent naming the component, around:
    • AeroError::Unsupported for tube fins the ring-wing model doesn’t take (fewer than three, solid, shorter than a third of their diameter, overlapping, or on a pod), canted fins on a pod, a pod’s tube of no length with a radius (a flat disc), or a part kind or fin cross-section this model doesn’t know (a nose shape the drag buildup has no data for builds, and the buildup refuses it when asked: AeroModel::drag);
    • AeroError::Domain for a fin set of more than eight fins, a non-finite station, a pod’s body with no fineness, or a drag input out of range (a negative fin thickness, a launch lug’s wall thicker than its radius, a rail button’s base and flange taller than the button, a negative roughness);
    • AeroError::Layout for a fin set or tube fin set without the radius of its body tube, or a pod’s body component listed before its pod set;
    • design errors from a profile, a planform, a volume integral or a pod set’s placements.
  • AeroError::Unsupported for motor mounts in more than MOTOR_POD_SETS pod sets, whose thrusting areas DragConditions can’t tell apart.
  • AeroError::Domain for a body-lift K that isn’t finite and non-negative.
Source

pub fn with_drag_table(self, table: DragTable) -> Self

This model with table replacing the drag buildup’s zero-lift drag (crate::table), and any drag model (AeroModel::with_drag_model).

Source

pub fn drag_table(&self) -> Option<&DragTable>

The drag override table, if any.

Source

pub fn with_drag_model(self, model: impl DragModel + 'static) -> Self

This model with model replacing the drag buildup’s zero-lift drag, and any drag table (crate::custom). The normal force, center of pressure and roll stay this model’s.

Source

pub fn with_shared_drag_model(self, model: Arc<dyn DragModel>) -> Self

As AeroModel::with_drag_model, with a model already shared: models that hold the same one are equal.

Source

pub fn drag_model(&self) -> Option<&Arc<dyn DragModel>>

The drag model in place of the buildup, if any.

Source

pub fn with_full_base_drag_under_power(self) -> Self

This model with the aft base’s drag kept whole while a motor burns: the thrusting motors’ cross-section is not taken off the base (DragConditions::thrusting_motor_area_m2 and the pods’ are read as zero), and a burning motor still selects a table’s power-on curve.

hpr’s own buildup takes it off, as Niskanen describes (2009, pp. 50–51: “if the base is the same size as the motor itself, no base drag”). OpenRocket 24.12 does not: on every one of its example designs’ flights of one branch, powered pods among them, its base-drag column is the whole base’s coefficient while a motor burns, as after, where the motors cover up to 94% of the reference area (validation/fixtures/ork/openrocket-base-drag.json, ADR-097). This is how a comparison with OpenRocket sizes that difference; it is not a better model. Neither rule has been checked against a measured flight.

Source

pub fn full_base_drag_under_power(&self) -> bool

Whether the aft base keeps its whole drag while a motor burns (AeroModel::with_full_base_drag_under_power).

Source

pub fn with_drag_scale(self, scale: f64) -> Result<Self, AeroError>

Multiplies every zero-lift drag coefficient AeroModel::drag gives by scale: the buildup’s (each of its five parts too), an override table’s or a drag model’s. A Monte Carlo run disperses drag this way, as RocketPy’s power_off_drag_factor and power_on_drag_factor do (rocketpy/stochastic/stochastic_rocket.py:745-746); the angle of attack’s factor, the normal force and the moments are not scaled. A table’s Drag::table lookup stays the table’s own value, and AeroModel::buildup_drag, what a drag model is given to adjust, stays unscaled.

§Errors

AeroError::Domain for a scale that is negative or not finite.

Source

pub fn drag_scale(&self) -> f64

The factor on every zero-lift drag coefficient (AeroModel::with_drag_scale); 1 unless set.

Source

pub fn supersonic_table_built(&self) -> bool

Whether the supersonic table (AeroModel::supersonic_body) has been built, by this model or by one sharing it (AeroModel::share_supersonic_table). A flight builds it the first time its flow passes Mach 1.2.

Source

pub fn share_supersonic_table(&mut self, other: &AeroModel) -> bool

Takes other’s supersonic table (AeroModel::supersonic_body) in place of this model’s own, when the two would build the same table: when they cover the same segments on the same reference area, the only inputs the table is built from. Then whichever model first needs the table builds it once for both, and for every clone of either, and the flights they fly are unchanged, bit for bit. Building the table takes up to about 125 runs of the shock-expansion method, a fifth of a second or more, so many flights of one airframe share it this way: a Monte Carlo run, whose samples change masses, motors, drag scale and weather but not the shape.

Returns true if the table is now shared. It returns false, and changes nothing, for another shape or reference area, or for a model with no table to build: one whose body the shock-expansion method doesn’t cover from the nose (a blunt nose, for one), which keeps slender-body theory past Mach 1.2.

Source

pub fn with_normal_force_table( self, table: NormalForceTable, ) -> Result<Self, AeroError>

This model with table replacing the whole rocket’s normal force and center of pressure (AeroModel::normal_force). Each component’s own terms stay hpr’s (AeroModel::components, AeroModel::component_normal_force): a flight engine takes its pitch and yaw damping from them, which a table doesn’t give.

§Errors

AeroError::Domain for a center of pressure in the table outside the rocket, from its nose tip to its aft end: the sign of a length in the wrong unit or from another datum. Only the Mach numbers a flight can use are checked, up to NORMAL_FORCE_MACH_LIMIT and the first past it; a hypersonic row may move where it likes.

Source

pub fn normal_force_table(&self) -> Option<&NormalForceTable>

The normal-force override table, if any.

Source

pub fn drag_terms(&self) -> &[ComponentDragTerms]

The components’ precomputed drag terms, in layout order.

Source

pub fn length_m(&self) -> f64

Rocket length for the Reynolds number: nose tip to the aft end of the last body component, m.

Source

pub fn drag( &self, flow: &Flow, conditions: &DragConditions, ) -> Result<Drag, AeroError>

The whole rocket’s drag at flow and conditions: the zero-lift drag of the buildup, or of the override table or drag model when there is one, and the axial coefficient at the flow’s angle of attack.

§Errors
Source

pub fn buildup_drag( &self, flow: &Flow, conditions: &DragConditions, ) -> Result<Drag, AeroError>

The drag buildup’s drag at flow and conditions, whatever override the model has: the sum of every component’s zero-lift terms, and the axial coefficient at the flow’s angle of attack. Without an override it is AeroModel::drag; with one, what the override replaces, which a drag model can adjust (crate::custom::DragQuery::buildup).

§Errors

As AeroModel::drag without an override.

Source

pub fn buildup_components( &self, flow: &Flow, conditions: &DragConditions, ) -> Result<Vec<ComponentDrag>, AeroError>

Each component’s share of the drag buildup at flow and conditions, in layout order: its zero-lift coefficient and parts, and its axial coefficient at the flow’s angle of attack.

These are always the buildup’s terms. With an override table or a drag model, AeroModel::drag returns its value instead of their sum, so they don’t add up to it.

§Errors

As AeroModel::drag without a table, and DragConditions::validate.

Source

pub fn reference_area_m2(&self) -> f64

Reference area, m².

Source

pub fn reference_diameter_m(&self) -> f64

Reference diameter, m: the length the rolling moment is taken on.

Source

pub fn roll(&self, mach: f64) -> Result<Roll, AeroError>

The whole rocket’s rolling moment at mach about +z_B, on the reference area and diameter: C_l = C_l0 + C_lp (p d/2V), with p the roll rate about +z_B and V the airspeed. Each fin set adds C_l0 = −N C_lδ k_T(B) δ and N C_lp k_R(B) (FinAero::roll, roll_forcing_interference, roll_damping_interference); a positive cant δ turns each fin’s leading edge toward −y_B at fin 0, so its lift rolls the rocket toward −z_B. Fin–fin interference is not applied to roll, as in Niskanen 2009 eq. 3.66. The airframe’s bodies of revolution add nothing. A pod’s body parts damp the roll by C_lp = −2 C_Nα ρ²/d² per pod, ρ its distance from the axis, and a pod’s fins damp it by the strips’ distance from the rocket’s axis (PodFins); a pod adds no forcing.

§Errors

AeroError::Mach outside [0, 5), as AeroModel::normal_force, and AeroError::Mach at Mach 0.8 and above on a rocket with tube fins (crate::tube_fins::TUBE_FIN_MACH_LIMIT).

Source

pub fn steady_roll_rate_rad_s( &self, mach: f64, speed_m_s: f64, ) -> Result<f64, AeroError>

The steady roll rate about +z_B, rad/s, at mach and airspeed speed_m_s in axial flow: where the fins’ forcing and damping balance, p = −(C_l0/C_lp)(2V/d). Zero with no fins.

§Errors

As AeroModel::roll, and AeroError::Domain for a negative or non-finite airspeed.

Source

pub fn bodies(&self) -> &[BodyAero]

The airframe’s body components’ terms; a pod’s are in Self::pod_sets.

Source

pub fn supersonic_body(&self) -> Option<&SupersonicBody>

The shock-expansion method’s shares of the nose, the cylinders and boattails behind it, and where they join slender-body theory; None where the method can’t take the body (a nose steeper than a blunt tip’s handover all the way to its base, a tangent cone past TN 3527’s Fig. 2, a later body with a slope of its own such as a flare) or doesn’t hold across a whole join below Mach 5.

The first call builds the table, which takes up to about 125 runs of the method; a flow no faster than SUPERSONIC_JOIN_START_MACH never needs it.

Source

pub fn supersonic_fallback(&self) -> Option<SupersonicFallback>

Why the shock-expansion method doesn’t fly this body faster than sound, or None when it does (Self::supersonic_body is Some). Like that, the first call may build the table. A body with no run at all, such as one read back from JSON, gives Other.

Source

pub fn body_lift_factor(&self, flow: &Flow) -> f64

The body-lift factor at flow, on (A_plan/A_ref) sin² α: Jorgensen’s η C_dn at the body’s fineness and the crossflow Mach number M sin α, or Galejs’s K (BodyModel::body_lift).

Source

pub fn body_model(&self) -> BodyModel

The body model: its body-lift and supersonic-boattail rules.

Source

pub fn fineness(&self) -> f64

The body’s length over its largest diameter, which sets body lift’s η.

Source

pub fn fin_sets(&self) -> &[FinSetAero]

The fin sets’ terms.

Source

pub fn rolls(&self) -> bool

Whether the normal force depends on the direction the air crosses the rocket: a fin set of one or two fins, whose share of its force in a plane varies with the plane (crate::roll_sum), and no normal-force table, which gives one force in every plane.

Source

pub fn tube_fin_sets(&self) -> &[TubeFinSetAero]

The tube fin sets’ terms.

Source

pub fn pod_sets(&self) -> &[PodSetAero]

The pod sets’ terms: those whose pods hold a body component with a size.

Source

pub fn component_count(&self) -> usize

The number of components with a normal-force term: the airframe’s bodies, the pods’ bodies, the fin sets, then the tube fin sets, in the order of Self::components.

Source

pub fn tube_fin_set_start(&self) -> usize

The index of the first tube fin set among the components (Self::components): the bodies and the fin sets come before.

Source

pub fn fin_set_start(&self) -> usize

The index of the first fin set among the components (Self::components): the bodies, the airframe’s and the pods’, come before. Every component from here is a lifting surface: the fin sets, then the tube fin sets (Self::tube_fin_set_start).

Source

pub fn component_normal_force( &self, index: usize, flow: &Flow, ) -> Result<NormalForce, AeroError>

Component index’s normal force at flow, in the order of Self::components, without allocating. A flight engine evaluates each component at its own local flow, which includes the airspeed the body’s rotation adds at the component.

§Errors

As Flow::validate, AeroError::Mach at Mach 0.8 and above for a tube fin set, and AeroError::Domain for an index past Self::component_count.

Source

pub fn component_station_m( &self, index: usize, mach: f64, ) -> Result<f64, AeroError>

The station, m aft of the nose tip, where a flight engine takes component index’s local airspeed at mach.

It is the component’s small-angle center of pressure wherever one model carries it: a fin set’s own, and a body’s moment_slope / slope, or its body-lift station where it has no potential-flow slope (a cylinder). Where two models share it, it is not: faster than sound a nose’s or cylinder’s station is joined linearly from slender-body theory’s to the method’s as the weight rises (SupersonicBody), while the force blends slopes and moments, so the two agree only at the ends of the join. On a lip riding half in its boattail’s wake, which never reaches an end, the tests’ tube sits 0.114 m (about two calibres) behind its own center of pressure (issue #106, which measures it and holds what a fix has to settle). A covered boattail, and a cylinder behind it, keep slender-body theory’s station: their shares may cross zero, where a station would run off to infinity.

§Errors

AeroError::Mach outside [0, 5), or [0, 0.8) for a tube fin set (crate::tube_fins::TUBE_FIN_MACH_LIMIT), and AeroError::Domain for an index past Self::component_count.

Source

pub fn normal_force(&self, flow: &Flow) -> Result<NormalForce, AeroError>

The whole rocket’s normal force at flow: the sum of its components, or the override table’s when there is one (AeroModel::with_normal_force_table).

A table’s normal force acts in the plane of the flow at the table’s center of pressure, with no side force; its coefficients are rescaled to the rocket’s reference area from the table’s (crate::table::TableReference).

§Errors

As Flow::validate, and without a table AeroError::Mach at Mach 0.8 and above on a rocket with tube fins (crate::tube_fins::TUBE_FIN_MACH_LIMIT). With a table, any finite Mach number from 0 is accepted (AeroError::Domain otherwise), and table errors are returned.

Source

pub fn components( &self, flow: &Flow, ) -> Result<Vec<ComponentNormalForce>, AeroError>

Each component’s normal force at flow: the airframe’s bodies, then the pods’ bodies (each over all its pods), then fin sets, then tube fin sets, each in layout order. A step in radius is part of the component aft of it.

These are always hpr’s own terms. With a normal-force table, AeroModel::normal_force returns the table’s value instead of their sum.

§Errors

As Flow::validate, and AeroError::Mach at Mach 0.8 and above on a rocket with tube fins (crate::tube_fins::TUBE_FIN_MACH_LIMIT).

Trait Implementations§

Source§

impl Clone for AeroModel

Source§

fn clone(&self) -> AeroModel

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AeroModel

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for AeroModel

Source§

fn eq(&self, other: &AeroModel) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for AeroModel

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for AeroModel

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.