Skip to main content

Material

Struct Material 

Source
pub struct Material {
    pub comp: BTreeMap<NuclideId, f64>,
    /* private fields */
}
Expand description

A nuclear material: nuclide masses plus optional density and metadata.

The composition stores absolute masses per nuclide, in grams by convention; only relative amounts matter for fraction-based consumers, which normalize on demand. Density is deliberately separate from the composition: it is a property of the physical stream and is not scaled or combined by the arithmetic operators except where noted.

Combining two materials clears density and metadata (a mixture has no single density); scalar scaling preserves them.

Fields§

§comp: BTreeMap<NuclideId, f64>

Stored masses (grams) keyed by nuclide.

Implementations§

Source§

impl Material

Source

pub fn from_formula( formula: &str, masses: &impl MassProvider, abundances: &impl AbundanceProvider, density: Option<f64>, ) -> FormulaResult<Self>

Build a material from a chemical formula, expanding each element into its naturally occurring isotopes.

Mirrors Material::from_atom_frac: atom counts come from the parsed formula weighted by natural-abundance fractions, stored masses are n_i * M_i using masses, and density is attached unchanged. Fails with the parse/abundance variants of FormulaError for bad input and with FormulaError::Core wrapping crate::Error::MissingMass when an isotope’s mass is unknown.

Source

pub fn expand_elements( &mut self, masses: &impl MassProvider, abundances: &impl AbundanceProvider, ) -> FormulaResult<()>

Replace natural-element placeholder entries with their isotopic breakdown, preserving each entry’s stored mass.

Placeholders follow the mcnp-io inp convention: a bare elemental zaid (z*1000, AAA == 0) becomes the nucid z * 10_000_000 (is_elemental). Each placeholder of element z holding g grams is replaced by isotope masses g * x_i * M_i / M̄, where x_i are the (normalized) natural-abundance fractions and the abundance-weighted mean atomic mass — i.e. the same number of atoms of each isotope as the elemental entry implied. Explicitly named nuclides are left untouched, so mixed elemental + isotopic compositions are supported.

Fails with FormulaError::NoAbundanceData when the provider has no isotopes for an element, or FormulaError::Core wrapping crate::Error::MissingMass when an isotope mass is unknown.

Source

pub fn collapse_elements(&self) -> Self

Inverse grouping of Material::expand_elements: fold every nuclide into its element’s placeholder row keyed by the natural-element id z * 10_000_000 (zaid z*1000). Placeholder entries already carry that key and simply accumulate alongside collapsed nuclides. Density and metadata are preserved; masses are summed exactly.

Source§

impl Material

Source

pub fn new() -> Self

An empty material.

Source

pub fn from_atom_frac( atoms: &[(NuclideId, f64)], masses: &impl MassProvider, density: Option<f64>, ) -> Result<Self>

Build a material from atom counts/fractions, converting to masses via m_i = n_i * M_i with atomic masses from masses.

Entries with zero atom count are skipped. Fails with crate::Error::MissingMass if any nonzero entry lacks a known atomic mass.

Source

pub fn add_nuclide(&mut self, id: NuclideId, mass: f64)

Add mass grams of id, accumulating when already present.

Source

pub fn remove_nuclide(&mut self, id: NuclideId) -> Option<f64>

Remove a nuclide, returning its stored mass if present.

Source

pub fn clear(&mut self)

Drop the entire composition (density and metadata are kept).

Source

pub fn mass(&self) -> f64

Total stored mass in grams.

Source

pub fn density(&self) -> Option<f64>

Mass density previously set on this material, if any.

Source

pub fn set_density(&mut self, density: Option<f64>)

Set (or unset) the mass density.

Source

pub fn metadata(&self) -> Option<&Value>

Free-form metadata attached to this material.

Source

pub fn set_metadata(&mut self, metadata: Option<Value>)

Replace the free-form metadata.

Source

pub fn weight_fractions(&self) -> Result<BTreeMap<NuclideId, f64>>

Normalized weight fractions; they sum to one.

Source

pub fn atom_fractions( &self, masses: &impl MassProvider, ) -> Result<BTreeMap<NuclideId, f64>>

Normalized atom fractions; they sum to one.

Each nuclide contributes moles proportional to mass / M; atomic masses come from masses.

Source

pub fn mix_by_mass(parts: &[(&Material, f64)]) -> Result<Self>

Mix streams weighted by relative mass amounts.

Fractions need not sum to one; they are relative weights of each stream’s full mass.

Source

pub fn mix_by_volume(parts: &[(&Material, f64)]) -> Result<Self>

Mix streams weighted by relative volumes, converting each stream’s contribution through its own density (m = v * rho). Every input must have a positive density set.

Source

pub fn separate(&self, effs: &[(NuclideId, f64)]) -> Result<(Self, Self)>

Split this material into product and tails streams by per-nuclide separation efficiency.

Each listed nuclide sends the fraction eff of its stored mass to the product stream and 1 - eff to the tails stream; nuclides absent from effs send nothing to product (eff = 0). Mass is conserved per nuclide: product + tails == self up to floating-point rounding. Efficiencies must be finite values in [0, 1] (else crate::Error::InvalidEfficiency); a repeated nuclide keeps its last-listed efficiency. Both outputs clear density and metadata (a split stream has no single density), and nuclides with exactly zero mass on a side are dropped from that side.

Source

pub fn blend(parts: &[(&Material, f64)]) -> Result<Self>

Blend streams at fixed ratios with explicit normalization.

Ratios are relative target proportions: they are normalized by their sum (w_i = r_i / Σr) and the output is the weighted average Σ w_i · mat_i (density and metadata cleared, as for the arithmetic operators). Unlike the cycamore mixer this never falls back to a silent uniform split: an empty slice or an all-zero (or non-finite) ratio sum fails with crate::Error::Degenerate, and any negative or non-finite ratio fails with crate::Error::NegativeFraction.

Source§

impl Material

Source

pub fn activity( &self, analytics: &Analytics<'_>, ) -> Result<BTreeMap<NuclideId, f64>, AnalyticsError>

Activity A = λ·N per nuclide, in becquerels.

Atom counts follow from stored masses through masses (N = m / (M · u) with u = 1.66053906892e-24 g) and decay constants through decays. Stable-as-zero: a known atomic mass with no decay constant is a stable nuclide (λ = 0, mirroring the chain rule where None decay → 0.0) and contributes exactly 0.0. Fails with AnalyticsError::Core wrapping crate::Error::MissingMass when an atomic mass is unknown, so genuinely unknown nuclides never collapse to silent zeros.

Source

pub fn specific_activity( &self, analytics: &Analytics<'_>, ) -> Result<f64, AnalyticsError>

Specific activity of the whole material, in Bq/g: total activity divided by total stored mass. Fails with AnalyticsError::Core for empty or non-positive materials; otherwise identical error behavior to Material::activity.

Source

pub fn decay_heat( &self, analytics: &Analytics<'_>, energies: &impl DecayEnergyProvider, ) -> Result<BTreeMap<NuclideId, f64>, AnalyticsError>

Decay heat per nuclide, in watts: P_i = A_i · E_i.

Activities come from Material::activity (masses via analytics, decay constants via analytics.decays); mean recoverable energies per decay come from energies in MeV, converted with MEV_TO_JOULES. Energies are screening-level placeholders (see DecayEnergies), so heat numbers are order-of-magnitude checks, not calorimetry.

Fails with AnalyticsError::MissingEnergy for radioactive nuclides without a decay-energy row; stable nuclides (zero activity, hence P = A·E = 0 regardless of E) skip the energy lookup and contribute exactly 0.0. Otherwise identical error behavior to Material::activity.

Source

pub fn total_decay_heat( &self, analytics: &Analytics<'_>, energies: &impl DecayEnergyProvider, ) -> Result<f64, AnalyticsError>

Total decay heat of the whole material, in watts: the sum of Material::decay_heat. Same error behavior.

Source

pub fn dose_per_g( &self, analytics: &Analytics<'_>, doses: &impl DoseProvider, pathway: DosePathway, source: DoseSource, ) -> Result<BTreeMap<NuclideId, f64>, AnalyticsError>

Dose per gram per nuclide, mirroring PyNE Material::dose_per_g.

For weight fraction w_i = m_i / m_tot:

dose_i = Ci_per_Bq · N_A · w_i · λ_i · DF_i / M_i   (air/soil)
dose_i = pCi_per_Bq · N_A · w_i · λ_i · DF_i / M_i  (ingest/inhale)

with CI_PER_BQ = 2.7027027e-11, PCI_PER_BQ = 27.027027, N_A = AVOGADRO (PyNE uses 6.0221415e23; the difference is <0.1 ppm), λ from analytics.decays, M (g/mol) from analytics.masses, and DF from doses. Units follow the table: air mrem/h per g per m^3, soil mrem/h per g per m^2, ingest/inhale mrem per g. The returned map holds each nuclide’s per-gram contribution; sum for the total.

Screening-level only — not for safety decisions. Stable nuclides (known mass, λ = 0 or absent) contribute exactly 0.0 and skip the doses lookup entirely, so no AnalyticsError::MissingDose is raised for them. Fails with AnalyticsError::MissingDose when a radioactive nuclide’s factor is absent or negative (-1 GENII/DOE air sentinel); otherwise identical error behavior to Material::activity (plus Degenerate for empty materials).

Source

pub fn total_dose_per_g( &self, analytics: &Analytics<'_>, doses: &impl DoseProvider, pathway: DosePathway, source: DoseSource, ) -> Result<f64, AnalyticsError>

Total dose per gram of the whole material: the sum of Material::dose_per_g. Same units and error behavior.

Source§

impl Material

Source

pub fn to_xml(&self, name: &str, density: f64, units: &str) -> Result<String>

Serialize this material as a <material> XML fragment.

Components are written as weight fractions (wo attributes). The density and its units are taken from the arguments rather than from Material::density, matching the free-standing export style.

Trait Implementations§

Source§

impl Add for Material

Source§

fn add(self, rhs: Material) -> Material

Combine two mass streams: per-nuclide masses add. Density and metadata are cleared on the mixture. Nuclides whose combined mass is exactly zero are dropped.

Source§

type Output = Material

The resulting type after applying the + operator.
Source§

impl Add<f64> for Material

Source§

fn add(self, rhs: f64) -> Material

Raise the total mass by rhs grams while preserving relative composition. Density is unchanged.

§Panics

If the current mass is non-positive or the new total would be.

Source§

type Output = Material

The resulting type after applying the + operator.
Source§

impl Clone for Material

Source§

fn clone(&self) -> Material

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 Material

Source§

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

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

impl Default for Material

Source§

fn default() -> Material

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for Material

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 Div<f64> for Material

Source§

fn div(self, rhs: f64) -> Material

Divide every stored mass by rhs (density unchanged).

§Panics

If rhs is zero.

Source§

type Output = Material

The resulting type after applying the / operator.
Source§

impl Mul<f64> for Material

Source§

fn mul(self, rhs: f64) -> Material

Scale every stored mass by rhs (density unchanged).

Source§

type Output = Material

The resulting type after applying the * operator.
Source§

impl PartialEq for Material

Source§

fn eq(&self, other: &Material) -> 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 Material

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 Material

Source§

impl Sub for Material

Source§

fn sub(self, rhs: Material) -> Material

Remove a mass stream: per-nuclide masses subtract. Density and metadata are cleared. Nuclides whose combined mass is exactly zero are dropped.

Source§

type Output = Material

The resulting type after applying the - operator.
Source§

impl Sub<f64> for Material

Source§

fn sub(self, rhs: f64) -> Material

Lower the total mass by rhs grams while preserving relative composition.

§Panics

If the current mass is non-positive or the remainder would be.

Source§

type Output = Material

The resulting type after applying the - operator.

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 = !

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

fn try_from(value: U) -> Result<T, !>

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.