Skip to main content

Substance

Struct Substance 

Source
pub struct Substance {
    pub name: String,
    pub density: Density,
    pub thermal: Option<ThermalProps>,
    pub mechanical: Option<MechanicalProps>,
    pub acoustic: Option<AcousticProps>,
}
Expand description

A material, as much of it as is known.

Fields§

§name: String

What it is called. Free text: a catalogue designation, a common name, whatever the caller will recognise in a violation message.

§density: Density

kg·m⁻³. The one property everything has, which is why it is not optional.

§thermal: Option<ThermalProps>

Conductivity, specific heat, emissivity and a service limit, if they are known.

Optional because a substance is often only known as far as it needed to be. A domain asking for what is not here gets None rather than a plausible default, which is the difference between “unknown” and “zero”.

§mechanical: Option<MechanicalProps>

Stiffness, restitution and friction, if they are known.

§acoustic: Option<AcousticProps>

Sound speed and absorption, if they are known.

Implementations§

Source§

impl Substance

Source

pub fn diffusivity(&self) -> Option<Diffusivity>

Thermal diffusivity, α = k / (ρ c_p) — the m²/s that decides how fast a temperature front moves, as opposed to how much heat flows.

This is the number that sets an explicit heat solver’s stability limit (dt < dx²/2α), so a thermal domain asks for it before it can say how big a step it can take.

Source

pub fn heat_capacity(&self, volume: Volume) -> Option<HeatCapacity>

Heat capacity of a given volume of this substance.

Source

pub fn mass_of(&self, volume: Volume) -> Mass

Mass of a given volume of it.

Source

pub fn expansion_of(&self, length: Length, rise: Temperature) -> Option<Length>

How much a length of this substance grows for a temperature rise. Linear, which is a good approximation for the tens of kelvin an instrument sees and a poor one for hundreds.

Source

pub fn constrained_stress(&self, rise: Temperature) -> Option<Pressure>

Stress produced by preventing that expansion — the reason a lens bonded rigidly into a metal mount cracks when it warms up.

σ = E α ΔT, independent of size, which is why scaling the part down does not help.

Source

pub fn survives(&self, rise: Temperature) -> Option<bool>

Whether that stress would break it.

Source

pub fn borosilicate_crown() -> Substance

N-BK7, the borosilicate crown that most of an optical bench is made of.

Source

pub fn aluminium_6061() -> Substance

6061 aluminium: what the mount holding the glass is made of, and the reason a mount-and-lens pair moves when the room does — its expansion is three times the glass’s.

Source

pub fn with_emissivity(self, emissivity: f64) -> Substance

The same substance with a different surface finish.

Emissivity is a property of the surface and not of the material, so anodised aluminium is not a new entry in the catalogue — it is aluminium_6061().with_emissivity(0.9). The factor of ten between polished and anodised 6061 lands squarely on the radiative loss path, which is the same order as still-air convection at room temperature.

Clamped to 0..=1: a surface cannot radiate more than a blackbody, and a negative emissivity would make a body warm itself.

Does nothing to a substance whose thermal properties are unknown, because None means unknown rather than zero and inventing three of the four fields to set the fourth would be worse than declining.

Source

pub fn with_specific_heat(self, specific_heat: SpecificHeat) -> Substance

The same substance with a different heat capacity.

For the assembly case: a motor, a populated board, a printed part with infill. The bulk c_p of a mixture is not the c_p of its main constituent, and this is the field where that difference is worth a factor of two.

Does nothing to a substance whose thermal properties are unknown, for the reason in Substance::with_emissivity.

Source

pub fn copper() -> Substance

Electrolytic tough-pitch copper: windings, heat spreaders, planes.

The values are uncontroversial to three figures. The emissivity is not: this is bright polished copper at 0.04, and copper oxidises — a tarnished surface runs 0.4 to 0.8, a factor of fifteen on the radiative path. If the part has been in air for a week, say so with Substance::with_emissivity.

Source

pub fn fr4() -> Substance

FR-4 glass-epoxy laminate: the board a driver sits on.

The conductivity is the through-plane one, 0.3 W/m/K, and that is the number a designer wants because it is the one heat has to cross to reach the far side. In-plane it is nearer 0.8, because the copper-free glass weave conducts better along its fibres — a factor of about three, and ThermalProps carries one scalar, so the choice has to be stated rather than averaged. Any real board is dominated by its copper pour anyway, which is not laminate at all.

The expansion is likewise in-plane, 14 ppm/K. Through-thickness FR-4 expands four to five times faster and goes higher again above its glass transition, which is what breaks plated through-holes; that regime is not modelled here.

Source

pub fn electrical_steel() -> Substance

Non-oriented silicon electrical steel: motor and transformer laminations.

Grade-dependent, and the spread is wide. Silicon content trades core loss against conductivity: 25 W/m/K here is mid-range for non-oriented sheet, and grades run from about 20 to 30. Stacked laminations conduct far worse across the stack than the sheet does, because the interlaminar varnish dominates — a stack is not this substance at all, and treating it as one overstates the conduction out of a motor.

Emissivity 0.3 is varnished sheet; bare mill finish is lower and rusty is much higher.

Source

pub fn pla() -> Substance

Solid cast PLA: printed structure, if it were solid, which it is not.

A printed part is not this substance. Infill and layer adhesion move the effective conductivity and density more than the polymer chemistry does: at 20% infill the density is a fifth of this and the through-layer conductivity is lower again, because the path crosses voids and weld lines rather than bulk. Scale the density by the infill fraction at the very least, and treat the conductivity as an upper bound.

That is not a caveat about precision. It is the difference between a part that survives and one that creeps: PLA softens around 60 °C, and Substance::survives is checking against a number the print may not reach in practice.

Source

pub fn water() -> Substance

Water at 20 °C.

Source

pub fn bulk(name: &str, density: Density) -> Substance

A substance with nothing known but how heavy it is.

Trait Implementations§

Source§

impl Clone for Substance

Source§

fn clone(&self) -> Substance

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 Substance

Source§

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

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

impl<'de> Deserialize<'de> for Substance

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl PartialEq for Substance

Source§

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

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

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

Inequality operator !=. Read more
Source§

impl Serialize for Substance

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 Substance

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> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

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.